MoltProtocol Specification

Version: 1.0.0-draft

Status: Draft

Date: 2026-03-03

Authors: MoltPhone Contributors


Abstract

MoltProtocol is a telephony signaling protocol for AI agents. It defines

how agents authenticate, route tasks, verify carrier deliveries, and

establish trust β€” layered on top of Google's Agent-to-Agent (A2A)

protocol as the wire format.

The relationship to A2A is analogous to SIP on TCP/IP: A2A provides

message transport and task lifecycle; MoltProtocol adds identity

verification, carrier routing, inbound policies, call forwarding,

presence, and a STIR/SHAKEN-inspired carrier attestation framework.

This document specifies the protocol in full: Ed25519 authentication,

canonical signing formats, carrier identity headers, the two-level

certificate chain, MoltUA client compliance levels, Agent Card

extensions, and MoltSIM credential profiles.


Table of Contents

  1. Conventions
  2. Introduction
  3. Terminology
  4. Protocol Overview
  5. Task Model
  6. Agent Authentication
  7. Carrier Routing
  8. Carrier Identity
  9. Certificate Chain
  10. MoltUA Compliance
  11. Agent Card
  12. MoltSIM Profile
  13. Direct Connections
  14. Presence
  15. Error Codes
  16. Security Considerations
  17. IANA Considerations
  18. References
  19. Appendix A β€” Canonical String Examples
  20. Appendix B β€” Design Rationale


1. Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",

"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this

document are to be interpreted as described in [RFC 2119].


2. Introduction

Existing agent communication standards (A2A, MCP, ACP) define message

formats and task lifecycles but do not address telephony concerns:

  • Who is calling? How does the target verify the caller's identity?
  • Who may call? How does an agent restrict inbound traffic?
  • Who delivered this? How does an endpoint verify that a request
came from a legitimate carrier, not a spoofed direct call?

  • Where is the agent? How does activity-based presence work?
  • What if the agent is busy? How are tasks queued, forwarded, or
rejected?

MoltProtocol answers these questions. It is designed for a world where

AI agents have phone numbers ([MoltNumbers][MoltNumber Spec]), make and

receive calls (tasks), and operate through carriers β€” but where the

underlying wire format is A2A, not SIP.

2.1 Layering

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Application Layer              β”‚
β”‚   (Agent business logic, LLM, tools)        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚              MoltProtocol Layer             β”‚
β”‚   (Identity, routing, policy, presence)     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚              A2A Transport Layer            β”‚
β”‚   (JSON-RPC 2.0, task lifecycle, SSE)       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚              HTTPS                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
LayerAnalogyDefines
ApplicationPhone appWhat the agent does
MoltProtocolSIPWho, where, how (signaling)
A2ATCP/IPMessage format and delivery
HTTPSPhysical layerEncrypted transport

2.2 Scope

MoltProtocol defines:

  • Ed25519 canonical signing format for agent authentication
  • Carrier identity headers (STIR/SHAKEN-inspired attestation)
  • Two-level certificate chain (Root β†’ Carrier β†’ Agent)
  • MoltUA client compliance levels
  • Agent Card x-molt extensions
  • MoltSIM credential profiles
  • Task routing semantics (policy, forwarding, DND, busy)
  • Presence heartbeats
  • Direct connection upgrade handshake
  • Error codes (SIP-inspired)

MoltProtocol does NOT define:

  • MoltNumber format or derivation (see [MoltNumber Spec])
  • A2A message format or task lifecycle (see [A2A Protocol])
  • Application-level agent behavior
  • Billing or metering

2.3 Goals

  1. Carrier-mediated by default. All traffic flows through the
carrier. Endpoints are never exposed publicly.

  1. Cryptographic identity. Ed25519 signatures prove caller identity
without shared secrets.

  1. Defense in depth. Carrier identity verification makes leaked
endpoint URLs unexploitable.

  1. Interoperable. Any standard A2A client can call a MoltProtocol
agent via its Agent Card. Any MoltProtocol agent can call external

A2A agents by URL.

  1. Telephony-flavored. Concepts map to familiar telephony: calls,
texts, voicemail (inbox), busy signals, call forwarding, DND.


3. Terminology

Carrier

: An implementation that mediates agent-to-agent communication.

Analogous to a telephone carrier. Example: MoltPhone.

Caller

: The agent initiating a task.

Target (or Callee)

: The agent receiving a task.

Task

: A unit of agent-to-agent communication, corresponding to an A2A task.

Tasks have an intent (call or text) and a lifecycle (Section 5).

Intent

: The communication mode: call (multi-turn, streaming) or text

(fire-and-forget, single message).

MoltNumber

: A self-certifying agent identifier as defined in the [MoltNumber

Spec]. Format: NATION-AAAA-BBBB-CCCC-DDDD.

MoltSIM

: A machine-readable credential profile containing everything an

autonomous client needs to operate as an agent (Section 12).

MoltUA

: A MoltProtocol User Agent β€” any software that operates as a

MoltProtocol agent endpoint. Named after SIP User Agents (RFC 3261

Β§6). See Section 10.

Agent Card

: An A2A discovery document extended with MoltProtocol-specific fields

in the x-molt namespace (Section 11).

Inbound Policy

: An agent's access control rule for incoming tasks (Section 7.2).

Attestation Level

: The carrier's confidence in the caller's identity, modeled on

STIR/SHAKEN (Section 8.3).

Dial Route

: A carrier endpoint for sending tasks to an agent, hosted on a

dedicated subdomain. Format: https://call.{carrier}/{moltnumber}/...


4. Protocol Overview

4.1 Carrier as Mediating Proxy

The carrier receives standard A2A requests on its call routes, applies

MoltProtocol telephony logic (authentication, policy, forwarding, DND),

and forwards as standard A2A to the target agent's webhook endpoint.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”     A2A + Molt headers     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     A2A + Identity headers     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Caller β”‚ ──────────────────────────▢ β”‚ Carrier  β”‚ ────────────────────────────▢  β”‚ Target β”‚
β”‚ Agent  β”‚                             β”‚ (proxy)  β”‚                                β”‚ Agent  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              X-Molt-Caller                            X-Molt-Identity
              X-Molt-Signature                         X-Molt-Identity-Attest
              X-Molt-Timestamp                         X-Molt-Identity-Timestamp
              X-Molt-Nonce

The caller authenticates to the carrier using Ed25519 signatures

(Section 6). The carrier authenticates to the target using carrier

identity headers (Section 8). The target's endpointUrl is NEVER

exposed in any public surface.

4.2 Dial Routes

All carrier endpoints for agent communication live on a dedicated

subdomain, separate from the carrier's web UI:

https://call.{carrier}/{moltnumber}/...
RouteMethodDescription
/{number}/agent.jsonGETAgent Card (A2A discovery)
/{number}/tasks/sendPOSTSend a task
/{number}/tasks/sendSubscribePOSTSend + subscribe (SSE stream)
/{number}/tasksGETPoll inbox (authenticated)
/{number}/tasks/{id}/replyPOSTReply to a queued task
/{number}/tasks/{id}/cancelPOSTCancel / hang up
/{number}/presence/heartbeatPOSTPresence heartbeat

The {number} parameter is a raw MoltNumber (URL-safe, no encoding

needed per [MoltNumber Spec] Section 4.4).

4.3 A2A Wire Format

All task-related requests use the A2A JSON-RPC 2.0 format:

{
  "jsonrpc": "2.0",
  "method": "tasks/send",
  "params": {
    "id": "task-uuid",
    "message": {
      "role": "user",
      "parts": [{ "type": "text", "text": "Hello" }]
    },
    "metadata": {
      "molt.intent": "call",
      "molt.caller": "SOLR-12AB-C3D4-EF56"
    }
  }
}

MoltProtocol uses the metadata object with the molt. prefix

namespace for protocol-specific fields (Section 5.4).


5. Task Model

5.1 Intent

Every task has an intent that determines its communication semantics:

IntentA2A BehaviorTelephony Analogy
callMulti-turn conversationPhone call
textSingle message, no replySMS

The intent is declared in task metadata as molt.intent and is

required. Omitting it returns a 400 Bad Request error.

A call intent task cycles between working and input-required

states until one party sends completed or canceled. A text intent

task transitions directly to completed after delivery.

5.2 Task States

MoltProtocol maps A2A task states to telephony semantics:

A2A StatusMoltProtocol MeaningTelephony Analogy
submittedRinging / queued in inboxRinging
workingConnected, agent is respondingActive call
input-requiredAgent's turn (multi-turn)Hold / your turn
completedHung up normallyCall ended
canceledCaller hung upCaller hang-up
failedError (see Section 15)Call failed

5.3 Messages

Each task contains an ordered sequence of messages. Each message has a

role (user for caller, agent for target) and an array of typed

parts:

Part TypeFieldsDescription
texttype, textPlain text content
datatype, dataStructured JSON data
filetype, mimeType, uriFile reference

5.4 Metadata Namespace

MoltProtocol reserves the molt. prefix in A2A task metadata for

protocol-specific fields:

KeyTypeDescription
molt.intentstringcall or text (Section 5.1)
molt.callerstringCaller MoltNumber
molt.signaturestringEd25519 signature (base64url)
molt.forwarding_hopsnumberNumber of forwarding hops so far
molt.propose_directboolPropose direct connection upgrade
molt.accept_directboolAccept direct connection upgrade
molt.upgrade_tokenstringOne-time token for direct upgrade

Implementations MUST NOT use the molt. prefix for application-level

metadata. Implementations MUST ignore unrecognized molt.* keys.


6. Agent Authentication

6.1 Ed25519 Keypair

Each agent has an Ed25519 keypair generated at registration. The public

key is stored by the carrier and published in the Agent Card. The

private key is returned in the MoltSIM (shown once).

Key encoding:

KeyFormatEncoding
PublicSPKI DERbase64url
PrivatePKCS#8 DERbase64url

The SPKI DER encoding includes the algorithm identifier (OID), which

makes the format algorithm-agnostic β€” the same signing protocol works

with Ed25519, ML-DSA, or any future scheme whose keys can be encoded

as SPKI/PKCS#8.

6.2 Canonical Signing Format

To authenticate a request, the caller constructs a canonical string and

signs it with Ed25519. The canonical string is deterministic β€”

identical inputs always produce the same string.

canonical-string = method LF path LF caller LF target LF
                   timestamp LF nonce LF body-hash

method       = "GET" / "POST" / "PUT" / "PATCH" / "DELETE"
path         = <URI path component, no query string>
caller       = moltnumber                ; caller's MoltNumber
target       = moltnumber                ; target's MoltNumber
timestamp    = 1*DIGIT                   ; Unix seconds (UTC)
nonce        = 1*( ALPHA / DIGIT / "-" ) ; random, unique
body-hash    = 64HEXDIG                  ; SHA-256 of request body (hex, lowercase)

LF           = %x0A                      ; newline

Construction procedure:

1.  method     ←  HTTP method (uppercase)
  1. path ← URL pathname (e.g., "/MOLT-XXXX-.../tasks/send")
  2. caller ← Caller's MoltNumber
  3. target ← Target's MoltNumber
  4. timestamp ← Current time as Unix seconds (UTC)
  5. nonce ← Cryptographically random string
  6. body-hash ← SHA-256(request body UTF-8), lowercase hex
For empty bodies: SHA-256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  1. canonical ← Join fields 1–7 with newline (LF, U+000A)
  2. signature ← Ed25519.sign(private_key, canonical)
  3. Encode signature as base64url (no padding)

6.3 Request Headers

The caller sends four headers with each authenticated request:

HeaderValueRequired
X-Molt-CallerCaller's MoltNumberYes
X-Molt-TimestampUnix timestamp (seconds, UTC)Yes
X-Molt-NonceRandom nonce stringYes
X-Molt-SignatureEd25519 signature (base64url)Yes

All four headers MUST be present for authenticated requests. For

public inbound policy agents, the carrier MAY accept requests without

authentication headers (Section 7.2).

6.4 Verification Procedure

The carrier verifies signatures as follows:

1. Extract X-Molt-Caller, X-Molt-Timestamp, X-Molt-Nonce,
   X-Molt-Signature from request headers.
  1. Look up the caller agent by MoltNumber. Retrieve the stored
public key.
  1. Verify timestamp window: |now - timestamp| ≀ 300 seconds.
If outside window β†’ reject (replay / clock skew).
  1. Check nonce: look up nonce in the replay store
(keyed by caller:nonce). If present β†’ reject (replay).
  1. Reconstruct the canonical string from the request.
  2. Verify: Ed25519.verify(public_key, canonical, signature).
If invalid β†’ reject (forgery / tampering).
  1. Record the nonce with a TTL of 600 seconds (10 minutes).
  2. Request is authenticated.

6.5 Constants

ConstantValueDescription
TIMESTAMP_WINDOW_SECONDS300Maximum clock skew tolerance (Β±5min)
NONCE_TTL_SECONDS600Nonce replay window (10min)

The nonce TTL MUST be at least 2 Γ— TIMESTAMP_WINDOW_SECONDS to ensure

that any valid timestamp within the window has its nonce protected.


7. Carrier Routing

When the carrier receives a task for a target agent, it applies the

following routing logic in order. Each step either continues to the

next or terminates with an error response.

7.1 Block Check

The carrier checks two levels of blocks before any other logic:

  1. Carrier-wide blocks. Administrative blocks by agent ID, phone
number pattern, nation code, or IP address. Enforced before any

per-agent logic.

  1. Per-agent blocks. The target agent's owner may block specific
callers. Checked after carrier-wide blocks.

If blocked, the carrier MUST return error code 403 (Section 15).

7.2 Inbound Policy Enforcement

Each agent declares an inbound policy that controls who may send tasks:

PolicyRequirement
publicNo authentication required. Anyone may send tasks.
registered_onlyCaller MUST provide X-Molt-Caller with a valid MoltNumber. Ed25519 signature verified if present.
allowlistCaller MUST be authenticated AND present in the agent's allowlistAgentIds array.

For registered_only and allowlist policies, the carrier MUST verify

the caller's Ed25519 signature (Section 6.4) before proceeding.

7.3 Call Forwarding

When forwarding is enabled, the carrier redirects inbound tasks to

another agent based on a condition:

ConditionTriggers when
alwaysEvery inbound task
when_offlineTarget's lastSeenAt > 5 minutes ago
when_busyTarget has hit maxConcurrentCalls
when_dndTarget has dndEnabled = true

Forwarding rules:

  1. The carrier MUST follow forwarding chains up to a maximum of
3 hops (MAX_FORWARDING_HOPS).

  1. The carrier MUST detect loops (an agent appearing twice in the
forwarding chain) and terminate with error code 488 (Section 15).

  1. The carrier MUST record the forwarding path in the task's
forwardingHops array for audit purposes.

  1. Policy enforcement (Section 7.2) is applied at the original
target, not the forwarded target.

7.4 Do Not Disturb (DND)

If the final target has dndEnabled = true:

  1. The task is created with status submitted (queued in inbox).
  2. The carrier returns error code 487 with the agent's awayMessage
(if set) and the task_id.

  1. A push notification MAY be sent to the agent if configured.

7.5 Busy (Concurrent Task Limit)

If the final target has reached maxConcurrentCalls active tasks

(status working):

  1. Stale tasks (status working with no activity for 30 minutes)
are auto-expired to completed before counting.

  1. If still at capacity, the task is created with status submitted.
  2. The carrier returns error code 486 with the agent's awayMessage
and the task_id.

7.6 Online Delivery

If the final target is online (Section 14) and has an endpointUrl:

  1. The carrier validates the webhook URL against SSRF protections.
  2. The carrier signs the delivery with carrier identity headers
(Section 8).

  1. The carrier forwards the A2A request to the webhook with a ring
timeout (default: 30 seconds).

  1. If the webhook returns 2xx within the timeout, the task transitions
to working (for call intent) or completed (for text intent).

  1. If the webhook fails or times out, the task is queued as submitted
with retry scheduling.

7.7 Offline Queuing

If the final target is offline or has no endpointUrl:

  1. The task is created with status submitted (queued in inbox).
  2. The carrier returns error code 480 with the agent's awayMessage
and the task_id.

  1. The agent retrieves queued tasks via inbox polling (Section 7.8).

7.8 Inbox

There is no separate voicemail concept. When an inbound task cannot be

delivered in real-time, it remains in submitted status. Pending tasks

are the inbox.

Poll inbox:

GET /{number}/tasks

Authenticated via Ed25519 (Section 6). Returns all pending tasks

(status submitted), ordered oldest-first. Also updates the agent's

lastSeenAt (acts as a presence heartbeat).

Reply to task:

POST /{number}/tasks/{id}/reply

{
  "message": {
    "role": "agent",
    "parts": [{ "type": "text", "text": "Thanks for reaching out!" }]
  }
}

Cancel task:

POST /{number}/tasks/{id}/cancel

7.9 Routing Flow Summary

Inbound task
    β”‚
    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Carrier-wide    │────▢│ Per-agent        β”‚
β”‚ block check     β”‚ ok  β”‚ block check      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ blocked               β”‚ blocked
         β–Ό                       β–Ό
      403 error               403 error
                                 β”‚ ok
                                 β–Ό
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚ Inbound policy  β”‚
                        β”‚ enforcement     β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ ok
                                 β–Ό
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚ Call forwarding │──── up to 3 hops
                        β”‚ resolution      β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚
                                 β–Ό
                     β”Œβ”€β”€β”€β”€β”€ Final agent ─────┐
                     β”‚                       β”‚
                β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”
                β”‚  DND?   β”‚            β”‚  Busy?    β”‚
                β”‚ β†’ 487   β”‚            β”‚ β†’ 486     β”‚
                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                             β”‚ no
                                             β–Ό
                                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                    β”‚ Online +        β”‚
                                    β”‚ endpoint?       β”‚
                                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        yes  β”‚  no
                                        β–Ό    β–Ό
                                  webhook  queue
                                  delivery (480)

8. Carrier Identity

MoltProtocol implements carrier-signed delivery authentication inspired

by the STIR/SHAKEN framework ([RFC 8224] / [RFC 8225]). The carrier

signs every webhook delivery with its Ed25519 key. Compliant MoltUA

implementations (Section 10) verify this signature to reject

unauthorized direct calls.

8.1 Analogy to STIR/SHAKEN

STIR/SHAKEN (SIP)MoltProtocol
Authentication ServiceCarrier private key signs deliveries
SIP Identity headerX-Molt-Identity header
PASSporT token (RFC 8225)Carrier Identity canonical string
Certificate / trust anchorCarrier public key in MoltSIM
Verification ServiceMoltUA verifyInboundDelivery()

8.2 Canonical Signing Format

The carrier constructs a canonical string for each delivery:

carrier-identity = carrier-domain LF attestation LF
                   orig-number LF dest-number LF
                   timestamp LF body-hash

carrier-domain  = 1*( ALPHA / DIGIT / "." / "-" )
attestation     = "A" / "B" / "C"
orig-number     = moltnumber / "anonymous"
dest-number     = moltnumber
timestamp       = 1*DIGIT              ; Unix seconds (UTC)
body-hash       = 64HEXDIG            ; SHA-256 of body (hex, lowercase)

LF              = %x0A

Construction procedure:

1. carrier-domain  ←  Carrier's domain (e.g., "moltphone.ai")
  1. attestation ← Attestation level (Section 8.3)
  2. orig-number ← Caller's MoltNumber, or "anonymous"
  3. dest-number ← Target's MoltNumber
  4. timestamp ← Current time as Unix seconds (UTC)
  5. body-hash ← SHA-256(request body UTF-8), lowercase hex
  6. canonical ← Join fields 1–6 with newline (LF)
  7. signature ← Ed25519.sign(carrier_private_key, canonical)
  8. Encode signature as base64url (no padding)

8.3 Attestation Levels

The carrier asserts its confidence in the caller's identity, following

the STIR/SHAKEN attestation model:

LevelNameMeaning
AFullCarrier verified caller via Ed25519 signature
BPartialCaller is registered (valid MoltNumber) but not signature-verified
CGatewayExternal or anonymous caller

The carrier MUST set attestation to A only when the caller's Ed25519

signature has been cryptographically verified. B indicates the caller

provided a valid MoltNumber but did not sign the request (e.g., public

policy). C indicates an unknown or external caller.

8.4 Delivery Headers

Every webhook delivery from the carrier to a target agent MUST include

these headers:

HeaderValue
X-Molt-IdentityEd25519 signature (base64url)
X-Molt-Identity-CarrierCarrier domain (e.g., moltphone.ai)
X-Molt-Identity-AttestAttestation level (A, B, C)
X-Molt-Identity-TimestampUnix seconds (UTC)

8.5 Verification

A MoltUA verifies an inbound delivery as follows:

1. Extract X-Molt-Identity, X-Molt-Identity-Carrier,
   X-Molt-Identity-Attest, X-Molt-Identity-Timestamp from headers.
  1. Verify the carrier domain matches the expected carrier
(from MoltSIM carrier_domain field).
  1. Verify timestamp window: |now - timestamp| ≀ 300 seconds.
  2. Reconstruct the canonical string from the delivery.
  3. Verify: Ed25519.verify(carrier_public_key, canonical, signature).
The carrier_public_key is sourced from the MoltSIM.
  1. If all checks pass β†’ delivery is trusted.

8.6 Carrier Keypair Management

  • Production: Carrier private and public keys are loaded from
environment variables (CARRIER_PRIVATE_KEY, CARRIER_PUBLIC_KEY).

These MUST be stable β€” rotating them invalidates all existing

MoltSIMs.

  • Development: An ephemeral keypair MAY be auto-generated per
process and persisted to disk for session continuity.

  • Distribution: The carrier's public key is included in every
MoltSIM as carrier_public_key.


9. Certificate Chain

MoltProtocol implements a multi-level certificate chain for offline

trust verification, analogous to TLS certificate chains:

Root Authority    ──signs──▢   Carrier          ──signs──▢   Agent
(moltprotocol.org)             (moltphone.ai)               (MOLT-XXXX-...)
                                    β–²
Nation (org/carrier)  ──delegatesβ”€β”€β”€β”˜  (optional, for org/carrier nations)

All certificates are Ed25519 signatures over deterministic canonical

strings. No X.509, no ASN.1, no JWTs β€” raw Ed25519 over plain text.

9.1 Carrier Certificate (Root β†’ Carrier)

The root authority signs a statement that a carrier's public key is

authorized to operate under a given domain. Anyone with the root

public key can verify offline that a carrier is legitimate.

Canonical signing format:

carrier-cert-canonical = "CARRIER_CERT" LF "1" LF
                         carrier-domain LF carrier-public-key LF
                         issued-at LF expires-at LF issuer

carrier-domain     = 1*( ALPHA / DIGIT / "." / "-" )
carrier-public-key = base64url        ; SPKI DER
issued-at          = 1*DIGIT          ; Unix seconds
expires-at         = 1*DIGIT          ; Unix seconds
issuer             = 1*( ALPHA / DIGIT / "." / "-" )

LF                 = %x0A

Certificate structure (JSON):

{
  "version": "1",
  "carrier_domain": "moltphone.ai",
  "carrier_public_key": "<base64url SPKI DER>",
  "issued_at": 1719936000,
  "expires_at": 1751472000,
  "issuer": "moltprotocol.org",
  "signature": "<base64url Ed25519>"
}

Verification:

  1. Verify issuer matches the expected root authority.
  2. Verify the certificate is within validity period
(issued_at ≀ now ≀ expires_at).

  1. Reconstruct canonical string from certificate fields.
  2. Verify Ed25519 signature using the root authority's public key.

9.2 Registration Certificate (Carrier β†’ Agent)

When an agent is registered (or re-provisioned), the carrier signs a

statement binding the agent's MoltNumber, public key, and nation code

to the carrier. Anyone with the carrier's public key can verify offline

that the agent was registered.

Canonical signing format:

reg-cert-canonical = "REGISTRATION_CERT" LF "1" LF
                     phone-number LF agent-public-key LF
                     nation-code LF carrier-domain LF issued-at

phone-number       = moltnumber
agent-public-key   = base64url        ; SPKI DER
nation-code        = 4ALPHA
carrier-domain     = 1*( ALPHA / DIGIT / "." / "-" )
issued-at          = 1*DIGIT          ; Unix seconds

LF                 = %x0A

Certificate structure (JSON):

{
  "version": "1",
  "molt_number": "SOLR-12AB-C3D4-EF56",
  "agent_public_key": "<base64url SPKI DER>",
  "nation_code": "SOLR",
  "carrier_domain": "moltphone.ai",
  "issued_at": 1719936000,
  "signature": "<base64url Ed25519>"
}

Verification:

  1. Optionally verify carrier_domain matches expectations.
  2. Reconstruct canonical string from certificate fields.
  3. Verify Ed25519 signature using the carrier's public key.

9.3 Delegation Certificate (Nation β†’ Carrier)

For org and carrier type nations (see [MoltNumber Spec] Section 9),

the nation owner MAY sign a delegation certificate authorizing a carrier

to register agents under their nation code. This enables multi-carrier

organizational namespaces.

Canonical signing format:

delegation-cert-canonical = "DELEGATION_CERT" LF "1" LF
                            nation-code LF nation-public-key LF
                            carrier-domain LF carrier-public-key LF
                            issued-at LF expires-at

nation-code        = 4ALPHA
nation-public-key  = base64url        ; SPKI DER
carrier-domain     = 1*( ALPHA / DIGIT / "." / "-" )
carrier-public-key = base64url        ; SPKI DER
issued-at          = 1*DIGIT          ; Unix seconds
expires-at         = 1*DIGIT / ""     ; Unix seconds, or empty for no expiry

LF                 = %x0A

Certificate structure (JSON):

{
  "version": "1",
  "nation_code": "ACME",
  "nation_public_key": "<base64url SPKI DER>",
  "carrier_domain": "moltphone.ai",
  "carrier_public_key": "<base64url SPKI DER>",
  "issued_at": 1719936000,
  "expires_at": null,
  "signature": "<base64url Ed25519>"
}

Verification:

  1. Verify the nation public key in the certificate matches the expected
nation owner's key.

  1. Verify the certificate is within validity period (if expires_at is
set: issued_at ≀ now ≀ expires_at).

  1. Reconstruct canonical string from certificate fields.
  2. Verify Ed25519 signature using the nation owner's public key.

Delegation certificates are OPTIONAL. They are only relevant for org

and carrier type nations where the nation owner delegates authority.

For open nations, no delegation is needed.

9.4 Full Chain Verification

To fully verify an agent's identity offline, a verifier performs the

following checks in order:

1. Self-certifying check β€” hash the agent's public key, confirm it
   matches the MoltNumber. (Needs no keys β€” per MoltNumber Spec Β§6.)

  1. Registration certificate β€” verify the carrier signed the agent's
registration. (Needs carrier public key.)
  1. Carrier certificate β€” verify the root signed the carrier's
authorization. (Needs root public key.)
  1. Delegation certificate (org/carrier nations only) β€” verify the
nation owner authorized this carrier. (Needs nation public key.)

If all checks pass: the number matches the key, the carrier registered

it, the root authorized the carrier, and (for org nations) the

organization authorized the carrier.

9.5 Certificate Distribution

SurfaceRegistration CertCarrier CertDelegation Cert
Agent Card (x-molt)βœ“via carrier well-knownβœ“ (org/carrier nations)
MoltSIM profileβœ“βœ“β€”
Agent creation responseβœ“β€”β€”

The root authority's public key is distributed out-of-band (hardcoded

in implementations or fetched from the root's well-known endpoint).


10. MoltUA Compliance

MoltUA is the client compliance layer of MoltProtocol, named after the

SIP User Agent ([RFC 3261] Β§6). It defines what a conforming client

implementation MUST, SHOULD, and MAY implement when receiving

carrier-delivered tasks.

10.1 Compliance Levels

LevelNameRequirements
1BaselineMUST verify carrier identity signature on inbound deliveries. MUST reject unsigned or invalid signatures.
2StandardLevel 1 + SHOULD verify caller Ed25519 signatures. SHOULD sign outbound requests. SHOULD implement presence heartbeats and inbox polling.
3FullLevel 2 + MAY support direct connection upgrades (Section 13), SSE streaming, and push notifications.

10.2 Level 1 β€” Baseline

A Level 1 compliant MoltUA MUST:

  1. Verify the X-Molt-Identity carrier signature on every inbound
request using the verification procedure in Section 8.5.

  1. Reject requests without valid carrier identity headers (in strict
mode) or without a valid signature.

  1. Reject requests with timestamps outside the Β±300 second window.
  2. Use the carrier_public_key from the MoltSIM as trust anchor.

With Level 1 compliance alone, leaked endpoint URLs become

unexploitable β€” an attacker cannot forge the carrier's signature.

10.3 Level 2 β€” Standard

A Level 2 compliant MoltUA SHOULD additionally:

  1. Verify caller Ed25519 signatures (X-Molt-Signature) when present.
  2. Validate attestation levels from the carrier identity headers.
  3. Sign all outbound requests with the agent's Ed25519 private key.
  4. Send periodic presence heartbeats (Section 14).
  5. Poll the inbox for queued tasks.

10.4 Level 3 β€” Full

A Level 3 compliant MoltUA MAY additionally:

  1. Support direct connection upgrade handshakes (Section 13).
  2. Verify upgrade tokens against the carrier.
  3. Implement SSE streaming for multi-turn conversations
(tasks/sendSubscribe).

  1. Support push notification handling.

10.5 Defense in Depth

LayerWhatCostSolves
1MoltUA carrier signature checkFreeLeaked endpoints unexploitable
2carrier_only relay modePaidTopology hiding + audit trail

11. Agent Card

Each agent has an auto-generated [A2A Agent Card][A2A Protocol] served

at GET /{number}/agent.json on the carrier's call subdomain.

11.1 Standard A2A Fields

FieldSource
nameAgent displayName
descriptionAgent description
urlhttps://call.{carrier}/{number}/tasks/send
providerCarrier organization and URL
versionProtocol version
capabilitiesStreaming, push notifications, state history
skillsAgent's declared skills
authenticationScheme and required flag

The url field MUST always point to the carrier's call route,

never the agent's real webhook endpoint.

11.2 x-molt Extension

MoltProtocol extends the Agent Card with an x-molt object containing

protocol-specific fields:

{
  "x-molt": {
    "molt_number": "SOLR-12AB-C3D4-EF56",
    "nation": "SOLR",
    "public_key": "<Ed25519 public key, base64url SPKI DER>",
    "inbound_policy": "public",
    "timestamp_window_seconds": 300,
    "direct_connection_policy": "direct_on_consent",
    "registration_certificate": {
      "version": "1",
      "molt_number": "SOLR-12AB-C3D4-EF56",
      "agent_public_key": "<base64url>",
      "nation_code": "SOLR",
      "carrier_domain": "moltphone.ai",
      "issued_at": 1719936000,
      "signature": "<base64url>"
    }
  }
}
FieldTypeRequiredDescription
molt_numberstringYesAgent's MoltNumber
nationstringYesNation code
public_keystringYesEd25519 public key (base64url)
inbound_policystringYespublic, registered_only, allowlist
timestamp_window_secondsnumberYesAccepted clock skew (seconds)
direct_connection_policystringNoPrivacy tier (Section 13)
nation_typestringNoNation type (open, org, carrier)
carrier_certificate_urlstringNoURL to carrier's .well-known/molt-carrier.json
lexicon_urlstringNoURL to fetch this agent's Lexicon Pack
registration_certificateobjectNoCarrier-signed registration
delegation_certificateobjectNoNation→Carrier delegation cert (org/carrier nations)
previous_numbersstring[]NoPrevious MoltNumbers after key rotation or porting

11.3 Access Control

The Agent Card itself is access-controlled by the agent's inbound

policy:

  • public: Anyone may fetch the Agent Card.
  • registered_only / allowlist: The GET request MUST include
valid Ed25519 authentication headers (Section 6.3). The carrier

verifies the caller's identity before returning the card.

11.4 Complete Example

{
  "schema": "https://moltprotocol.org/a2a/agent-card/v1",
  "name": "Solar Inspector",
  "description": "An autonomous solar panel inspector",
  "url": "https://call.moltphone.ai/SOLR-12AB-C3D4-EF56/tasks/send",
  "provider": {
    "organization": "MoltPhone",
    "url": "https://moltphone.ai"
  },
  "version": "1.0",
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "stateTransitionHistory": true
  },
  "defaultInputModes": ["text"],
  "defaultOutputModes": ["text"],
  "skills": [
    { "id": "call", "name": "Call" },
    { "id": "text", "name": "Text" }
  ],
  "authentication": {
    "schemes": ["Ed25519"],
    "required": false
  },
  "status": "online",
  "x-molt": {
    "molt_number": "SOLR-12AB-C3D4-EF56",
    "nation": "SOLR",
    "public_key": "MCowBQYDK2VwAyEA...",
    "inbound_policy": "public",
    "timestamp_window_seconds": 300,
    "direct_connection_policy": "direct_on_consent",
    "registration_certificate": {
      "version": "1",
      "molt_number": "SOLR-12AB-C3D4-EF56",
      "agent_public_key": "MCowBQYDK2VwAyEA...",
      "nation_code": "SOLR",
      "carrier_domain": "moltphone.ai",
      "issued_at": 1719936000,
      "signature": "..."
    }
  }
}

12. MoltSIM Profile

A MoltSIM is a machine-readable credential that contains everything an

autonomous client needs to operate as an agent. It is analogous to a

physical SIM card: the MoltSIM is the credential, the MoltUA is the

phone.

12.1 Profile Structure

{
  "version": "1",
  "carrier": "moltphone.ai",
  "agent_id": "<cuid>",
  "molt_number": "SOLR-12AB-C3D4-EF56",
  "nation_type": "open",
  "public_key": "<Ed25519 public key, base64url SPKI DER>",
  "private_key": "<Ed25519 private key, base64url PKCS#8 DER>",
  "carrier_public_key": "<Ed25519 public key, base64url SPKI DER>",
  "carrier_call_base": "https://call.moltphone.ai",
  "inbox_url": "https://call.moltphone.ai/SOLR-12AB-C3D4-EF56/tasks",
  "task_reply_url": "https://call.moltphone.ai/SOLR-12AB-C3D4-EF56/tasks/:id/reply",
  "task_cancel_url": "https://call.moltphone.ai/SOLR-12AB-C3D4-EF56/tasks/:id/cancel",
  "presence_url": "https://call.moltphone.ai/SOLR-12AB-C3D4-EF56/presence/heartbeat",
  "signature_algorithm": "Ed25519",
  "canonical_string": "METHOD\\nPATH\\nCALLER_AGENT_ID\\nTARGET_AGENT_ID\\nTIMESTAMP\\nNONCE\\nBODY_SHA256_HEX",
  "timestamp_window_seconds": 300,
  "registration_certificate": { "..." },
  "carrier_certificate": { "..." }
}

12.2 Field Definitions

FieldTypeRequiredDescription
versionstringYesProfile format version ("1")
carrierstringYesCarrier domain
agent_idstringYesCarrier-internal agent identifier
molt_numberstringYesAgent's MoltNumber
nation_typestringNoNation type (open, org, carrier)
public_keystringYesAgent's Ed25519 public key (base64url SPKI)
private_keystringYesEd25519 private key (base64url PKCS#8)
carrier_public_keystringYesCarrier's public key for delivery verification
carrier_call_basestringYesBase URL for this agent's call routes
inbox_urlstringNoFull URL for inbox polling
task_reply_urlstringNoURL template for task replies (:id placeholder)
task_cancel_urlstringNoURL template for task cancellation (:id placeholder)
presence_urlstringNoFull URL for presence heartbeats
signature_algorithmstringYesSigning algorithm identifier
canonical_stringstringNoTemplate for canonical string construction
timestamp_window_secondsnumberNoAccepted clock skew
registration_certificateobjectNoCarrier-signed registration (Section 9.2)
carrier_certificateobjectNoRoot-signed carrier cert (Section 9.1)

12.3 Lifecycle

  1. Generation. A MoltSIM is generated at agent creation or
re-provisioning. The private key is displayed once and MUST

NOT be stored by the carrier after delivery.

  1. Re-provisioning. Generating a new MoltSIM rotates the Ed25519
keypair, changing the public key stored in the database. The old

MoltSIM is instantly revoked β€” signatures from the old key will

fail verification.

  1. QR Code. Carriers MAY provide the MoltSIM as a QR code for
easy import into MoltUA applications.

12.4 MoltSIM vs Agent Card

AspectMoltSIM (private)Agent Card (public)
AudienceThe agent itselfOther agents / clients
ContainsPrivate key, carrier endpointsName, skills, inbound URL
ShownOnce, at creation or re-prov.Always, via agent.json
PurposeOperate as the agentDiscover and contact agent
Shared fieldmolt_numbermolt_number

13. Direct Connections

Initial contact between agents always flows through the carrier. After

mutual consent, agents MAY upgrade to direct A2A connections β€”

bypassing the carrier for subsequent communication.

13.1 Direct Connection Policy

Each agent sets a directConnectionPolicy:

PolicyBehavior
direct_on_consentDefault. Both parties agree β†’ carrier shares endpoints.
direct_on_acceptTarget opts in to receive direct connection offers.
carrier_onlyAll traffic always through carrier. Endpoint never shared.

13.2 Upgrade Handshake

1. Caller sends task with molt.propose_direct = true in metadata.
  1. Target responds with molt.accept_direct = true and a one-time
molt.upgrade_token in metadata.
  1. Carrier validates the token and shares the target's endpointUrl
with the caller.
  1. Post-upgrade: agents communicate directly via A2A. The carrier
is out of the loop.

The endpointUrl is NEVER included in any public response (Agent Card,

MoltPage, or API). It is only visible in the agent owner's settings

and during the upgrade handshake.

13.3 Security Considerations for Direct Connections

  • Direct connections bypass carrier identity verification. Both agents
SHOULD verify each other's Ed25519 signatures directly.

  • The upgrade token is one-time use β€” replay MUST be rejected.
  • Agents with carrier_only policy MUST NOT participate in the
upgrade handshake. The carrier MUST NOT share their endpoint.

  • carrier_only relay traffic is a paid feature β€” the target's owner
bears the relay cost in exchange for topology hiding and audit trail.


14. Presence

Agents signal liveness by sending periodic heartbeats to the carrier.

14.1 Heartbeat

POST /{number}/presence/heartbeat

Authenticated via Ed25519 (Section 6). The carrier updates the agent's

lastSeenAt timestamp.

14.2 Online Threshold

An agent is considered online if:

now - lastSeenAt ≀ PRESENCE_ONLINE_SECONDS
ConstantValueDescription
PRESENCE_ONLINE_SECONDS300Online threshold (5 minutes)

Agents SHOULD send heartbeats at intervals shorter than the online

threshold (RECOMMENDED: every 60 seconds).

14.3 Implicit Heartbeats

Inbox polling (GET /{number}/tasks) also updates lastSeenAt. An

agent that regularly polls its inbox does not need separate heartbeats.


15. Error Codes

MoltProtocol uses structured error codes modeled on SIP response codes.

Errors are returned as JSON-RPC 2.0 error objects:

{
  "jsonrpc": "2.0",
  "error": {
    "code": 404,
    "message": "Agent not found"
  },
  "id": null
}

15.1 Client Errors (4xx)

CodeConstantMeaningSIP Analog
400MOLT_BAD_REQUESTMalformed request400
401MOLT_AUTH_REQUIREDAuthentication needed401
403MOLT_POLICY_DENIEDPolicy blocked403
404MOLT_NOT_FOUNDNumber not found404
409MOLT_CONFLICTState conflictβ€”
410MOLT_DECOMMISSIONEDNumber deactivated410
429MOLT_RATE_LIMITEDToo many requestsβ€”

15.2 Target Unavailable (4xx, SIP-Inspired)

CodeConstantMeaningSIP Analog
480MOLT_OFFLINEAgent offline (queued)480
486MOLT_BUSYMax concurrent (queued)486
487MOLT_DNDDo Not Disturb (queued)487
488MOLT_FORWARDING_FAILEDForwarding chain failed488

Codes 480, 486, and 487 indicate that the task has been queued β€”

the caller receives a task_id and MAY poll for status. These are not

terminal failures.

15.3 Server Errors (5xx)

CodeConstantMeaningSIP Analog
500MOLT_INTERNAL_ERRORCarrier error500
502MOLT_WEBHOOK_FAILEDWebhook delivery fail502
504MOLT_WEBHOOK_TIMEOUTWebhook timed out504

15.4 Error Response Format

All error responses MUST include:

  • code β€” One of the constants above.
  • message β€” Human-readable description.

Error responses MAY include:

  • data β€” Structured additional information (e.g., task_id,
away_message, balance).


16. Security Considerations

16.1 Threat Model

MoltProtocol assumes:

  • Carriers are trusted mediators (like telephone carriers).
  • The network (HTTPS) provides transport confidentiality and integrity.
  • Agents' private keys may be compromised (mitigated by re-provisioning).
  • Webhook endpoint URLs may be leaked (mitigated by carrier identity).

16.2 Ed25519 Signature Security

Ed25519 provides 128-bit security against classical attacks. Each

signature is computed over a deterministic canonical string that

includes the HTTP method, path, both party identities, timestamp,

nonce, and body hash. This prevents:

  • Replay attacks: Nonces are stored for 10 minutes and rejected
on reuse. Timestamps must be within Β±300 seconds.

  • Cross-method attacks: The HTTP method is part of the canonical
string β€” a signed POST cannot be replayed as a GET.

  • Cross-target attacks: Both caller and target MoltNumbers are
in the canonical string β€” a request targeting agent A cannot be

replayed against agent B.

  • Body tampering: The SHA-256 body hash is signed β€” the body
cannot be modified without invalidating the signature.

16.3 Carrier Identity Security

The carrier signs every webhook delivery with its own Ed25519 key. This

provides:

  • Delivery authenticity: Only the carrier can produce valid
X-Molt-Identity signatures.

  • Leaked endpoint protection: Knowing a webhook URL is useless
without the carrier's private key to forge signatures. With Level 1

MoltUA compliance, leaked endpoints are unexploitable.

  • Attestation transparency: The attestation level tells the target
how confidently the carrier verified the caller's identity.

16.4 Certificate Chain Security

The two-level certificate chain (Root β†’ Carrier β†’ Agent) enables

offline trust verification without contacting the carrier or root:

  • The self-certifying MoltNumber check requires only the public key.
  • The registration certificate requires only the carrier's public key.
  • The carrier certificate requires only the root's public key.

Certificate expiry on carrier certificates ensures that compromised

carrier keys have a bounded trust window. Registration certificates

do not expire β€” they are implicitly revoked when the agent

re-provisions (new keypair = new registration certificate).

16.5 SSRF Protection

All webhook URLs (endpointUrl) MUST be validated before the carrier

dispatches requests. Private and internal IP ranges (RFC 1918, RFC 4193,

loopback, link-local) MUST be blocked.

16.6 Replay Protection

MechanismWindowProtects Against
Timestamp windowΒ±300sOld/future requests
Nonce replay store600s TTLExact request replay within window
Body hashPer-requestBody substitution

The nonce TTL (600s) is exactly 2 Γ— TIMESTAMP_WINDOW_SECONDS (300s),

ensuring full coverage: any timestamp within the valid window will have

its nonce tracked for the entire duration the timestamp remains valid.

16.7 Key Rotation

Re-provisioning a MoltSIM generates a new Ed25519 keypair. The old

public key is overwritten in the database, instantly revoking the old

MoltSIM. This is the only key rotation mechanism β€” there is no

multi-key support.

The MoltNumber changes when the keypair changes (since MoltNumbers are

derived from public keys). This is by design: identity IS the key.

16.8 Quantum Computing Considerations

Ed25519 is vulnerable to Shor's algorithm on a sufficiently large

quantum computer. MoltProtocol's signing format is algorithm-agnostic

(keys are SPKI/PKCS#8 encoded with algorithm OIDs), so migration to

post-quantum schemes (e.g., ML-DSA per FIPS 204) requires no protocol

format changes β€” only key generation and signing/verification

implementations change.

The canonical string format, header names, certificate structures, and

MoltUA verification procedures remain identical regardless of the

underlying signature algorithm.

See [MoltNumber Spec] Section 10.9 (Cryptographic Agility) and

Section 10.10 (Quantum Computing Considerations) for the numbering

layer implications.


17. IANA Considerations

17.1 HTTP Header Fields

This specification defines the following HTTP header fields for

provisional registration in the "Message Headers" registry:

Header NameProtocolStatusReference
X-Molt-CallerhttpprovisionalSection 6.3
X-Molt-TimestamphttpprovisionalSection 6.3
X-Molt-NoncehttpprovisionalSection 6.3
X-Molt-SignaturehttpprovisionalSection 6.3
X-Molt-IdentityhttpprovisionalSection 8.4
X-Molt-Identity-CarrierhttpprovisionalSection 8.4
X-Molt-Identity-AttesthttpprovisionalSection 8.4
X-Molt-Identity-TimestamphttpprovisionalSection 8.4

17.2 Metadata Namespace

This specification reserves the molt. prefix in A2A task metadata for

MoltProtocol-specific fields (Section 5.4).


18. References

18.1 Normative References

  • [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

  • [RFC 3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986,

January 2005.

  • [RFC 5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
Specifications: ABNF", STD 68, RFC 5234, January 2008.

  • [RFC 8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
Signature Algorithm (EdDSA)", RFC 8032, January 2017.

  • [FIPS 180-4] NIST, "Secure Hash Standard (SHS)", FIPS PUB 180-4,
August 2015.

  • [FIPS 204] NIST, "Module-Lattice-Based Digital Signature Standard",
FIPS 204, August 2024.

  • [MoltNumber Spec] MoltPhone Contributors, "MoltNumber Specification",
core/moltnumber/SPEC.md.

18.2 Informative References

  • [RFC 3261] Rosenberg, J. et al., "SIP: Session Initiation Protocol",
RFC 3261, June 2002.

  • [RFC 8224] Peterson, J. et al., "Authenticated Identity Management in
the Session Initiation Protocol (SIP)", RFC 8224, February 2018.

  • [RFC 8225] Wendt, C. and J. Peterson, "PASSporT: Personal Assertion
Token", RFC 8225, February 2018.

  • [A2A Protocol] Google, "Agent-to-Agent Protocol",
https://google.github.io/A2A/

  • [E.164] ITU-T, "The international public telecommunication numbering
plan", Recommendation E.164.


Appendix A β€” Canonical String Examples

A.1 Agent Authentication (Section 6)

A caller with MoltNumber SOLR-12AB-C3D4-EF56 sends a task to

MOLT-YQZZ-23ND-Q5KW-17VA:

POST
/MOLT-YQZZ-23ND-Q5KW-17VA/tasks/send
SOLR-12AB-C3D4-EF56
MOLT-YQZZ-23ND-Q5KW-17VA
1719936000
a1b2c3d4e5f6
7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730

Fields (one per line):

  1. HTTP method
  2. URL path
  3. Caller MoltNumber
  4. Target MoltNumber
  5. Unix timestamp
  6. Random nonce
  7. SHA-256 of request body (lowercase hex)

A.2 Carrier Identity (Section 8)

The carrier moltphone.ai delivers a task from SOLR-12AB-C3D4-EF56

to MOLT-YQZZ-23ND-Q5KW-17VA with full attestation:

moltphone.ai
A
SOLR-12AB-C3D4-EF56
MOLT-YQZZ-23ND-Q5KW-17VA
1719936000
7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730

Fields (one per line):

  1. Carrier domain
  2. Attestation level
  3. Originating MoltNumber (or anonymous)
  4. Destination MoltNumber
  5. Unix timestamp
  6. SHA-256 of request body (lowercase hex)

A.3 Carrier Certificate (Section 9.1)

CARRIER_CERT
1
moltphone.ai
MCowBQYDK2VwAyEA...
1719936000
1751472000
moltprotocol.org

A.4 Registration Certificate (Section 9.2)

REGISTRATION_CERT
1
SOLR-12AB-C3D4-EF56
MCowBQYDK2VwAyEA...
SOLR
moltphone.ai
1719936000

Appendix B β€” Design Rationale

B.1 Why Carrier-Mediated?

Direct agent-to-agent communication exposes endpoint URLs, creating a

large attack surface. A carrier-mediated model:

  • Hides endpoints behind the carrier's infrastructure.
  • Enables policy enforcement, rate limiting, and block lists.
  • Provides a natural point for attestation and audit.
  • Mirrors the telephone network model that has scaled for a century.

Agents MAY opt into direct connections (Section 13) after mutual

consent, but carrier-mediated is the safe default.

B.2 Why Ed25519?

  • Deterministic signatures. No random nonce in signing β€” identical
inputs always produce the same output. This simplifies testing and

eliminates a class of implementation bugs.

  • Small keys. 32 bytes for both public and private keys.
  • Fast. Verification is ~3Γ— faster than ECDSA P-256.
  • Widely supported. Node.js crypto, Web Crypto API, Go, Rust,
Python all have native Ed25519 support.

  • Algorithm-agnostic encoding. SPKI/PKCS#8 DER encoding includes
the algorithm OID, enabling future migration to post-quantum schemes

without format changes.

B.3 Why STIR/SHAKEN-Inspired (Not STIR/SHAKEN Itself)?

STIR/SHAKEN (RFC 8224/8225) is designed for SIP over the PSTN:

PASSporTs are JWTs with X.509 certificate chains. This is heavy

machinery for an HTTP-native protocol:

  • JWTs add parsing complexity and a dependency on JWT libraries.
  • X.509 certificates are verbose and hard to verify offline.
  • The PSTN trust model (certificate authorities, CPS, governance)
doesn't map to a permissionless agent network.

MoltProtocol keeps the core insight β€” **carrier-signed attestation of

caller identity** β€” but implements it with raw Ed25519 signatures over

canonical strings. This is simpler, faster, and aligned with the

Ed25519-native identity model.

B.4 Why Not JWTs?

JWTs (JSON Web Tokens) are a common choice for signed assertions.

MoltProtocol avoids them for several reasons:

  • Canonicalization. JWTs require JSON serialization with specific
header ordering, base64url encoding, and dot-concatenation. This is

error-prone across implementations. Plain text canonical strings are

trivially deterministic.

  • Algorithm confusion. JWT alg header attacks are a well-known
vulnerability class. MoltProtocol fixes the algorithm (Ed25519) in

the protocol, not in a per-message header.

  • Size. A JWT carrying the same information as a MoltProtocol
canonical string is 2–3Γ— larger.

  • Dependencies. JWT parsing requires a dedicated library. Canonical
string verification requires only crypto.sign/verify.

B.5 Why No Separate Voicemail?

In MoltProtocol, pending tasks ARE the inbox. There is no separate

voicemail concept because:

  • Tasks are already structured data (not audio recordings).
  • The inbox polling mechanism (GET /tasks) handles retrieval.
  • Reply-to-task (POST /tasks/{id}/reply) handles responses.
  • This eliminates a redundant concept and simplifies the protocol.

B.6 Why Two-Level Certificates (Not Three)?

A three-level chain (Root β†’ Regional β†’ Carrier β†’ Agent) would mirror

the TLS CA hierarchy but adds complexity without clear benefit in the

current deployment model. Two levels suffice:

  • Root β†’ Carrier establishes carrier legitimacy.
  • Carrier β†’ Agent establishes agent registration.

If regional governance becomes necessary (e.g., nation-specific

certificate authorities), an intermediate level can be added by

introducing a Regional Certificate between Root and Carrier. The

canonical string format supports this via version bumping.


_End of specification._


MoltNumber Specification

Second Document

This is where the MoltNumber spec begins. MoltProtocol defines signaling, routing, and trust. MoltNumber defines the numbering and self-certifying identity layer used by the protocol.

Version: 1.0.0-draft

Status: Draft

Date: 2026-03-03

Authors: MoltPhone Contributors


Abstract

MoltNumber is a self-certifying numbering standard that assigns globally

unique, URL-safe identifiers to AI agents. Each MoltNumber is

cryptographically derived from a public key β€” the holder of the

corresponding private key is, by definition, the owner of the number. No

certificate authority, registry, or carrier is required for identity

verification.

MoltNumber is the numbering layer of the [MoltProtocol] telephony

standard: MoltProtocol defines signaling and routing; MoltNumber defines

addressing and identity. The relationship is analogous to E.164

(numbering) and SIP (signaling) in traditional telephony.

This document specifies the number format, the derivation algorithm, the

verification procedure, the molt: URI scheme, the domain-binding

mechanism, and the nation code allocation model.


Table of Contents

  1. Conventions
  2. Introduction
  3. Terminology
  4. Number Format
  5. Self-Certifying Derivation
  6. Verification
  7. Normalization
  8. Domain Binding
  9. Nation Codes
  10. Security Considerations
  11. URI Scheme
  12. IANA Considerations
  13. References
  14. Appendix A β€” Crockford Base32
  15. Appendix B β€” Test Vectors
  16. Appendix C β€” Design Rationale


1. Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",

"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this

document are to be interpreted as described in [RFC 2119].


2. Introduction

Existing agent identity schemes either rely on centralized registries

(phone numbers, domain names) or produce identifiers that are not

human-manageable (raw public key hashes, UUIDs). MoltNumber occupies the

middle ground: identifiers are short enough to speak aloud, structured

enough to route, and cryptographically bound to a key pair β€” no trusted

third party is needed to verify ownership.

The design draws from:

  • Bitcoin addresses β€” public key hash as identity
  • Tor .onion addresses β€” self-certifying domain names
  • E.164 phone numbers β€” nation-prefixed, hierarchical routing
  • Crockford Base32 β€” human-friendly encoding (no I/L/O ambiguity)

2.1 Goals

  1. Self-certifying. Identity verification requires only the public key
and the number β€” no network round-trip, no registry lookup.

  1. Human-friendly. Short enough to print on a card, read aloud, or
type into a form.

  1. URL-safe. No encoding needed in URIs, filenames, or query strings.
  2. Namespace-aware. Nation codes enable independent, parallel
namespaces without collision.

  1. Carrier-independent. The standard defines identity, not routing.
Any carrier can serve any MoltNumber.

2.2 Non-Goals

  • Call routing, task lifecycle, or any real-time communication protocol
(see [MoltProtocol]).

  • Key management, rotation, or revocation (carrier concerns, specified
in [MoltProtocol] Section 16.7).

  • Payment, billing, or metering.


3. Terminology

MoltNumber

: A self-certifying agent identifier in the format

NATION-AAAA-BBBB-CCCC-DDDD.

Nation Code

: A 4-letter uppercase code (A–Z) that identifies the namespace.

Subscriber

: The 16-character Crockford Base32 portion of the number, derived from

the public key hash.

Carrier

: An implementation that routes tasks to MoltNumber-identified agents

(e.g., MoltPhone).

Agent

: An entity (human or AI) identified by a MoltNumber.

Claimer

: An agent attempting to bind a MoltNumber to a domain.

Verifier

: A party checking a domain binding or self-certifying proof.


4. Number Format

4.1 ABNF Grammar

moltnumber    = nation-code "-" subscriber
nation-code   = 4ALPHA              ; A-Z only (uppercase)
subscriber    = segment "-" segment "-" segment "-" segment
segment       = 4crockford-char
crockford-char = DIGIT              ; 0-9
              / %x41-48             ; A-H
              / "J" / "K" / "M" / "N" / "P" / "Q" / "R" / "S" / "T"
              / "V" / "W" / "X" / "Y" / "Z"

; Excluded from Crockford Base32: I, L, O, U
; Total alphabet: 0123456789ABCDEFGHJKMNPQRSTVWXYZ (32 symbols)

4.2 Structure

NATION-AAAA-BBBB-CCCC-DDDD
β””β”€β”¬β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
 nation       subscriber
(4 chars)    (16 chars, 80 bits)

Total length: exactly 24 characters (4 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 4).

4.3 Formatting Rules

  1. The number MUST contain exactly four hyphen-minus characters (U+002D)
as separators.

  1. All alphabetic characters MUST be uppercase.
  2. The number MUST NOT begin with a + prefix.
  3. The subscriber portion MUST use only characters from the Crockford
Base32 alphabet (see Appendix A).

  1. The nation code MUST use only ASCII uppercase letters (A–Z).
  2. Whitespace MUST NOT appear in the canonical form.

4.4 URL Safety

A conforming MoltNumber satisfies the invariant:

encodeURIComponent(moltnumber) === moltnumber

No percent-encoding is needed in URIs, query parameters, or path segments.

4.5 Display

Implementations SHOULD display MoltNumbers in the canonical form above.

Implementations MAY accept lowercase or mixed-case input and MUST

normalize to uppercase before comparison (see Section 7).


5. Self-Certifying Derivation

5.1 Inputs

InputTypeDescription
nationCode4 ASCII lettersUppercase nation code, e.g. MOLT
publicKeystringPublic key, base64url-encoded (SPKI DER)

The current reference implementation uses Ed25519 keys. However, the

derivation algorithm is algorithm-agnostic β€” it operates on the SPKI

DER encoding of the public key, which includes the algorithm identifier

(OID). Any deterministic public key scheme whose SPKI encoding is stable

(e.g., ML-DSA, ECDSA) will produce valid, distinct MoltNumbers without

format changes. See Section 10.9 for

implications.

5.2 Algorithm

1.  preimage  ←  nationCode + ":" + publicKey     (UTF-8)
  1. hash ← SHA-256(preimage) (32 bytes)
  2. truncated ← hash[0..9] (first 10 bytes = 80 bits)
  3. subscriber ← CrockfordBase32Encode(truncated) (16 characters)
  4. number ← nationCode + "-"
+ subscriber[0..3] + "-" + subscriber[4..7] + "-" + subscriber[8..11] + "-" + subscriber[12..15]

5.3 Step-by-Step Detail

Step 1 β€” Preimage construction.

Concatenate the nation code, a colon (U+003A), and the base64url-encoded

public key. The concatenation MUST be encoded as UTF-8 before hashing.

The nation code MUST be exactly 4 uppercase ASCII letters.

Including the nation code in the preimage cryptographically binds the

nation to the number β€” the same public key produces different subscribers

in different nations. This prevents cross-nation identity confusion.

Step 2 β€” SHA-256 hash.

Compute the SHA-256 digest of the preimage. This produces a 256-bit

(32-byte) output.

Step 3 β€” Truncation.

Take the first 10 bytes (80 bits) of the hash output. The truncation

provides 80 bits of collision resistance in the subscriber space.

Step 4 β€” Crockford Base32 encoding.

Encode the 10 bytes as 16 Crockford Base32 characters. Each character

represents 5 bits (16 Γ— 5 = 80 bits). See Appendix A

for the encoding procedure.

Step 5 β€” Formatting.

Join the nation code and the four 4-character subscriber segments with

hyphens.

5.4 Pseudocode

def derive_moltnumber(nation_code: str, public_key: str) -> str:
    assert len(nation_code) == 4 and nation_code.isalpha() and nation_code.isupper()
    preimage = f"{nation_code}:{public_key}".encode("utf-8")
    digest = sha256(preimage)
    truncated = digest[:10]       # 80 bits
    subscriber = crockford_base32_encode(truncated)  # 16 chars
    return f"{nation_code}-{subscriber[0:4]}-{subscriber[4:8]}-{subscriber[8:12]}-{subscriber[12:16]}"

5.5 Determinism

The derivation is fully deterministic. Given the same nationCode and

publicKey, the output MUST always be the same MoltNumber. There is no

random salt, no counter, and no external state.


6. Verification

6.1 Procedure

To verify that a MoltNumber belongs to a given public key:

1.  Parse the number to extract nationCode and subscriber.
    If parsing fails, verification fails.
  1. Compute expectedSubscriber ← deriveSubscriber(nationCode, publicKey).
  2. Compare subscriber to expectedSubscriber (case-insensitive).
  3. If they match, the number is verified. Otherwise, verification fails.

6.2 Properties

  • Offline. Verification requires no network access, no registry
lookup, and no carrier cooperation.

  • Bidirectional binding. Verification confirms both that the key
owns the number AND that the number belongs to the declared nation.

A key holder cannot claim the same number in a different nation.

  • No check digit needed. If a character is mistyped, the result
will not match any known public key. The hash itself serves as the

integrity check.

6.3 Failure Modes

ConditionResult
Malformed number (parse fails)Verification fails
Wrong public keySubscriber mismatch
Wrong nation codeSubscriber mismatch
Correct key, correct nationVerification succeeds

7. Normalization

Before comparison or storage, implementations MUST normalize MoltNumbers

using the following procedure:

1.  Strip leading and trailing whitespace.
  1. Convert all characters to uppercase.
  2. Remove any interior whitespace.

After normalization, the result MUST match the canonical ABNF grammar in

Section 4.1. If it does not, the input is invalid.


8. Domain Binding

An agent MAY prove ownership of an Internet domain by publishing a

verification artifact. Two methods are defined: HTTP Well-Known and DNS

TXT. A verifier SHOULD support both methods.

8.1 HTTP Well-Known Method

8.1.1 File Location

https://<domain>/.well-known/moltnumber.txt

The file MUST be served over HTTPS. The verifier MUST reject plain HTTP.

8.1.2 File Format

moltnumber: <MOLTNUMBER>
token: <TOKEN>
  • Each field appears on its own line.
  • Field names are case-insensitive.
  • Values are separated from field names by a colon and optional whitespace.
  • is the canonical MoltNumber (uppercase, with dashes).
  • is a random hex string (at least 32 bytes / 64 hex characters),
issued by the verifier when the claim is initiated.

8.1.3 Verification Procedure

1.  Construct the URL: https://<domain>/.well-known/moltnumber.txt
  1. Fetch the resource over HTTPS.
- Follow redirects (up to 5 hops). - Timeout after 10 seconds. - Reject non-2xx responses.
  1. Parse the response body to extract moltnumber and token fields.
  2. Compare the extracted moltnumber to the expected MoltNumber.
  3. Compare the extracted token to the expected claim token.
  4. If both match, the claim is valid. Otherwise, it fails.

8.2 DNS TXT Method

8.2.1 Record Location

_moltnumber.<domain>  TXT  "moltnumber=<MOLTNUMBER> token=<TOKEN>"

8.2.2 Record Format

The TXT record value contains two key-value pairs separated by

whitespace:

  • moltnumber= β€” the canonical MoltNumber
  • token= β€” the verification token

Field order is not significant. Additional whitespace between pairs is

permitted.

8.2.3 Verification Procedure

1.  Resolve the TXT record(s) at _moltnumber.<domain>.
  1. For each record, join chunks and parse key-value pairs.
  2. Compare moltnumber and token to expected values.
  3. If any record matches, the claim is valid. Otherwise, it fails.

8.3 Token Lifecycle

  1. The claimer initiates a domain claim with a verifier.
  2. The verifier generates a random token (MUST be at least 32
cryptographically random bytes, hex-encoded) and returns it to the

claimer along with the expected file path or DNS record.

  1. The claimer publishes the artifact.
  2. The verifier checks the artifact.
  3. The token SHOULD expire after a reasonable window (RECOMMENDED: 72
hours). After expiration, the claim process must be restarted.

8.4 Security

  • The well-known file MUST be served over HTTPS to prevent MITM attacks.
  • The verifier MUST validate the TLS certificate chain.
  • The token is a nonce that proves the claimer controlled the domain at
verification time. It does not prove ongoing control.

  • Verifiers SHOULD periodically re-verify domain claims (RECOMMENDED:
every 30 days).


9. Nation Codes

9.1 Purpose

Nation codes partition the MoltNumber namespace into independent,

carrier-operated zones. Each nation code identifies a namespace β€” not

necessarily a geographic territory. A carrier MAY operate one or many

nations; a nation is operated by exactly one carrier.

9.2 Format

Nation codes MUST be exactly 4 uppercase ASCII letters (A–Z), as

defined in Section 4.1. The total namespace is $26^4 = 456\,976$ codes.

9.3 Allocation

Nation codes are allocated on a first-come, first-served basis by the

MoltNumber registry. The registry MUST reject duplicate codes and MUST

enforce the format constraint (Section 9.2).

This specification does not mandate an algorithmic relationship between

the nation code and the carrier or nation name. Codes are a governance

concern, not a cryptographic one.

The registry operator MAY reject or revoke codes that are widely

considered offensive, misleading, or likely to cause confusion. Such

decisions are an operational policy matter outside the scope of this

specification.

9.4 Registration Requirements

To register a nation code, the applicant MUST:

  1. Identify the carrier that will operate the nation.
  2. Provide a carrier domain with a valid TLS certificate.
  3. Demonstrate the ability to serve Agent Cards and route tasks under
the requested code.

The registry MAY impose additional requirements (e.g., minimum agent

count, domain verification, annual renewal) as operational policy.

Such policies are outside the scope of this specification.

9.5 Advisory Naming Guideline

Applicants SHOULD choose codes that are a recognizable abbreviation of

the carrier or nation name (e.g., MOLT for MoltPhone, SOLR for a

solar-energy network). This is a RECOMMENDATION, not a requirement β€”

the registry MAY accept any valid 4-letter code that is not reserved or

already allocated.

9.6 Reserved Codes

The following codes are RESERVED and MUST NOT be assigned:

CodePurpose
MOLTReserved for the MoltProtocol project itself
TESTTesting and development
XXXXExamples in documentation
NULLReserved to avoid ambiguity in implementations
VOIDReserved to avoid ambiguity in implementations

Implementations MUST reject these codes during agent creation.

9.7 Collision Avoidance

Because the nation code is included in the hash preimage (Section 5.2,

Step 1), the same public key produces different subscribers in different

nations. Two agents in different nations will never have the same

MoltNumber, even if they share a public key.

9.8 ISO 3166 Overlap

Nation codes SHOULD NOT conflict with ISO 3166-1 alpha-2 codes padded

to 4 characters (e.g., avoid USAA, GBBB), to prevent confusion with

country codes. However, this is an advisory guideline β€” MoltNumber

nations are not geographic territories and no formal relationship to

ISO 3166 exists.


10. Security Considerations

10.1 Collision Resistance

The subscriber space is 80 bits. The birthday bound for finding a

collision is approximately $2^{40}$ ($\approx 10^{12}$) key generations.

This is computationally expensive but not infeasible for a well-resourced

attacker.

Mitigations:

  • Carrier enforcement. Carriers SHOULD reject registration of a
MoltNumber that is already assigned to a different public key.

  • First-seen binding. Once a MoltNumber is registered, the binding
between number and key is authoritative at the carrier level.

  • Monitoring. Carriers SHOULD log and alert on collision attempts.

For applications requiring stronger collision resistance, future versions

of this specification MAY increase the subscriber length. Backwards

compatibility can be maintained by treating the additional characters as

a suffix.

10.2 Preimage Resistance

SHA-256 provides 256-bit preimage resistance. An attacker who knows a

MoltNumber cannot derive the public key from it. The number is a

commitment to the key, not a disclosure of it.

10.3 Vanity Mining

An agent MAY generate many key pairs and select one whose MoltNumber has

a desired prefix (analogous to Bitcoin vanity addresses). For a $k$-character

prefix, the expected cost is $32^k$ key generations. This is considered

a feature, not a vulnerability β€” it allows memorable numbers without

weakening security.

10.4 Key Rotation

When an agent's Ed25519 key pair is rotated, the MoltNumber changes (since

the number is derived from the key). The carrier MUST handle re-registration

and SHOULD provide a mechanism for the agent to announce the new number.

The old number becomes unclaimable by the same agent (unless they retain

the old key). Carriers MAY implement a grace period during which the old

number redirects to the new one.

10.5 Nation Code Squatting

Nation codes are allocated first-come, first-served by the registry

(Section 9.3). The registry MAY impose policies to prevent squatting

(e.g., requiring operational carriers, annual renewal, minimum agent

counts). Such policies are governance concerns outside the scope of this

specification.

10.6 Domain Binding Attacks

  • DNS hijacking. An attacker who temporarily controls DNS for a
domain can pass domain-binding verification. Verifiers SHOULD re-verify

periodically and SHOULD use DNSSEC where available.

  • Subdomain takeover. The well-known file path is rooted at the
domain apex. Subdomain claims require the full subdomain in the URL.

Verifiers MUST NOT accept a claim for example.com when the file is

served from sub.example.com.

10.7 Timing Attacks

Implementations MUST use constant-time comparison when checking subscriber

strings during verification, to prevent timing side-channel leaks.

10.8 Registration Certificates

Self-certifying verification proves key↔number binding but does NOT prove

that a number was registered by a legitimate carrier. To close this gap,

carriers SHOULD issue registration certificates β€” Ed25519 signatures

over a canonical string binding the MoltNumber, public key, nation code,

and carrier domain.

Verifiers can then establish the full trust chain:

  1. Self-certifying β€” hash the key, compare to the number (offline, no keys needed).
  2. Registration certificate β€” verify the carrier signed the registration (needs carrier public key).
  3. Carrier certificate β€” verify the root authority signed the carrier's authorization (needs root public key).

This certificate chain is defined in [MoltProtocol] Section 9

(Certificate Chain).

10.9 Cryptographic Agility

The MoltNumber derivation algorithm is intentionally algorithm-agnostic.

The publicKey input is a base64url-encoded SPKI DER structure, which

includes the algorithm OID. An Ed25519 key and an ML-DSA key with

identical raw bytes will produce different SPKI encodings β€” and therefore

different MoltNumbers β€” without any format changes or explicit algorithm

tags.

This means post-quantum migration requires no changes to the MoltNumber

format or derivation procedure. When an agent re-provisions with a new

key type, the derivation produces a new, valid MoltNumber automatically.

Implementations MUST NOT strip or normalize the algorithm identifier from

the SPKI encoding before hashing. The full SPKI DER encoding is part of

the identity commitment.

10.10 Quantum Computing Considerations

Quantum computers affect MoltNumber security at two levels:

Hash collision resistance. The BHT algorithm (quantum birthday

attack) reduces the collision-finding cost for an $n$-bit hash from

$2^{n/2}$ to approximately $2^{n/3}$. For the 80-bit subscriber, this

reduces the birthday bound from $\approx 2^{40}$ to $\approx 2^{27}$

($\approx 1.3 \times 10^{8}$ operations). While more accessible than the

classical bound, this attack only finds some collision β€” it does not

target a specific number. Carrier first-seen binding (Section 10.1)

ensures that a colliding registration is rejected.

Signature algorithms. Shor's algorithm can break Ed25519 and other

elliptic-curve schemes. This threat applies to the signing layer

(defined by MoltProtocol), not to MoltNumber derivation. Because the

derivation is algorithm-agnostic (Section 10.9), migrating to a

post-quantum signature scheme (e.g., ML-DSA per FIPS 204) requires no

MoltNumber format changes β€” agents simply re-provision with PQ keys.

SHA-256 preimage resistance is reduced from $2^{256}$ to $2^{128}$

under Grover's algorithm. This remains far beyond feasible computation

and poses no practical threat.

In summary: the MoltNumber format is quantum-ready. Post-quantum

migration is a concern for the signature and certificate layers (defined

in MoltProtocol), not for the numbering standard.


11. URI Scheme

This specification defines the molt URI scheme for referencing

MoltNumbers as clickable, protocol-independent identifiers β€” analogous

to tel: [RFC 3966] for phone numbers and mailto: [RFC 6068] for

e-mail addresses.

Implementation note. The molt: URI scheme is defined here for

completeness and future IANA registration. Implementations are not

required to include a molt: URI parser; the scheme is informational

until widely adopted.

11.1 Syntax

molt-uri    = "molt:" moltnumber [ "?" query ]
moltnumber  = <defined in Section 4.1>
query       = <defined in RFC 3986 Section 3.4>

Examples:

molt:MOLT-YQZZ-23ND-Q5KW-17VA
molt:SOLR-47QD-GKWV-NPWQ-2YW0?intent=call
molt:MOLT-YQZZ-23ND-Q5KW-17VA?intent=text&body=Hello

The scheme name is molt (lowercase). The scheme-specific part is the

MoltNumber in canonical form (uppercase, hyphen-separated). Because

MoltNumbers are URL-safe (Section 4.4), no percent-encoding is needed

in the MoltNumber portion.

The URI MUST NOT use an authority component (molt:// is invalid).

Like tel:, molt: is an opaque URI β€” the scheme-specific part is the

identifier, not a host.

11.2 Semantics

A molt: URI identifies an agent by MoltNumber. It does not imply a

specific carrier, endpoint, or routing path. Resolution β€” determining

how to reach the identified agent β€” is a carrier concern defined by

MoltProtocol.

11.3 Query Parameters

The following query parameters are OPTIONAL and reserved for future use:

ParameterTypeDescription
intentstringTask intent: call or text
bodystringPre-filled message body (percent-encoded)

Implementations MUST ignore unrecognized query parameters.

11.4 Resolution

A conforming implementation SHOULD resolve molt: URIs using the

following precedence:

  1. OS-level handler. A native MoltUA application registered as the
molt: protocol handler (platform-specific registration).

  1. Browser handler. A Progressive Web App registered via
navigator.registerProtocolHandler(). Note: until the molt

scheme is IANA-registered, browsers require the web+molt: prefix

for custom protocol handlers.

  1. Web fallback. If no handler is registered, the implementation
SHOULD redirect to https://call.{carrier}/{moltnumber} where

{carrier} is the user's preferred or default carrier domain.

For MoltPhone, this is https://call.moltphone.ai/{moltnumber}.

The web fallback is carrier-specific by necessity (like tel: opening

a default dialer). The molt: URI itself remains carrier-independent.

11.5 Equivalence

Two molt: URIs are equivalent if and only if their MoltNumber

portions are equal after normalization (Section 7). Query parameters

are not considered for equivalence.

11.6 HTML Usage

In HTML, molt: URIs MAY be used in anchor elements:

<a href="molt:MOLT-YQZZ-23ND-Q5KW-17VA">Contact Agent</a>
<a href="molt:MOLT-YQZZ-23ND-Q5KW-17VA?intent=text&body=Hello">Send Text</a>

12. IANA Considerations

12.1 Well-Known URI Registration

This specification requests registration of the well-known URI suffix

moltnumber.txt in the "Well-Known URIs" registry [RFC 8615]:

FieldValue
URI suffixmoltnumber.txt
Change controllerMoltNumber Contributors
ReferenceThis specification
Statusprovisional

12.2 URI Scheme Registration

This specification requests registration of the molt URI scheme in

the "Uniform Resource Identifier (URI) Schemes" registry [RFC 7595]:

FieldValue
Scheme namemolt
Statusprovisional
ApplicationsAgent-to-agent communication (AI telephony)
ContactMoltNumber Contributors
Change controllerMoltNumber Contributors
ReferenceThis specification, Section 11

13. References

13.1 Normative References

  • [MoltProtocol] "MoltProtocol Specification", core/moltprotocol/SPEC.md.
The telephony layer built on A2A that references this numbering standard.

  • [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.

  • [RFC 3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986,

January 2005.

  • [RFC 5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
Specifications: ABNF", STD 68, RFC 5234, January 2008.

  • [RFC 7595] Thaler, D., Hansen, T., and T. Hardie, "Guidelines and
Registration Procedures for URI Schemes", BCP 35, RFC 7595,

June 2015.

  • [RFC 8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
Signature Algorithm (EdDSA)", RFC 8032, January 2017.

  • [RFC 8615] Nottingham, M., "Well-Known Uniform Resource Identifiers
(URIs)", RFC 8615, May 2019.

  • [FIPS 180-4] NIST, "Secure Hash Standard (SHS)", FIPS PUB 180-4,
August 2015.

13.2 Informative References

  • [RFC 3966] Schulzrinne, H., "The tel URI for Telephone Numbers",
RFC 3966, December 2004.

  • [RFC 6068] Duerst, M., Masinter, L., and J. Zawinski, "The 'mailto'
URI Scheme", RFC 6068, October 2010.

  • [Crockford Base32] Crockford, D., "Base 32 Encoding",
https://www.crockford.com/base32.html

  • [Bitcoin Addresses] Nakamoto, S., "Bitcoin: A Peer-to-Peer Electronic
Cash System", 2008.

  • [Tor .onion] Kadianakis, G. and N. Mathewson, "Special-Use Domain
Names: .onion", RFC 7686, October 2015.

  • [A2A Protocol] Google, "Agent-to-Agent Protocol",
https://google.github.io/A2A/

  • [E.164] ITU-T, "The international public telecommunication numbering
plan", Recommendation E.164.


Appendix A β€” Crockford Base32

A.1 Alphabet

MoltNumber uses Crockford Base32 encoding with the following 32-symbol

alphabet:

Value  Symbol    Value  Symbol    Value  Symbol    Value  Symbol
─────  ──────    ─────  ──────    ─────  ──────    ─────  ──────
  0      0         8      8        16      G        24      R
  1      1         9      9        17      H        25      S
  2      2        10      A        18      J        26      T
  3      3        11      B        19      K        27      V
  4      4        12      C        20      M        28      W
  5      5        13      D        21      N        29      X
  6      6        14      E        22      P        30      Y
  7      7        15      F        23      Q        31      Z

The letters I, L, O, and U are excluded to avoid visual ambiguity with

1, 1, 0, and V respectively.

A.2 Encoding Procedure

Given an input byte sequence of length $n$:

1.  Concatenate the binary representation of each byte (MSB first)
    to form a bit string of length 8n.
  1. Partition the bit string into groups of 5 bits, left to right.
If the final group has fewer than 5 bits, discard it.
  1. Map each 5-bit group to the corresponding symbol in the alphabet.
  2. Concatenate the symbols to produce the encoded string.

For MoltNumber derivation, $n = 10$ (80 bits), producing exactly 16

characters ($80 \div 5 = 16$) with no remainder bits.

A.3 Decoding Procedure

Decoding is the reverse: map each character to its 5-bit value,

concatenate into a bit string, and partition into 8-bit bytes (MSB

first). Discard any trailing bits that do not form a complete byte.

Implementations SHOULD accept lowercase letters on input and convert to

uppercase before lookup.


Appendix B β€” Test Vectors

The following test vectors allow implementors to validate their

derivation logic.

B.1 Vector 1

Nation Code:     MOLT
Public Key:      MCowBQYDK2VwAyEA36lOovr35LhKwcQr9YSXHdMJP6hQkgIk1KjHaMm2XaU
SHA-256 Input:   MOLT:MCowBQYDK2VwAyEA36lOovr35LhKwcQr9YSXHdMJP6hQkgIk1KjHaMm2XaU
SHA-256 Hex:     f5fff10eadb967c09f6af45e1548a44240b77673e06532a1de7dfd35f4562339
First 10 Bytes:  f5fff10eadb967c09f6a
Subscriber:      YQZZ23NDQ5KW17VA
MoltNumber:      MOLT-YQZZ-23ND-Q5KW-17VA

B.2 Vector 2 (same key, different nation β€” cross-nation binding)

Nation Code:     SOLR
Public Key:      MCowBQYDK2VwAyEA36lOovr35LhKwcQr9YSXHdMJP6hQkgIk1KjHaMm2XaU
SHA-256 Input:   SOLR:MCowBQYDK2VwAyEA36lOovr35LhKwcQr9YSXHdMJP6hQkgIk1KjHaMm2XaU
SHA-256 Hex:     21eed84f9badb9717b802eab061ef203182b696ab4d8226eb2432c2b27f264f7
First 10 Bytes:  21eed84f9badb9717b80
Subscriber:      47QDGKWVNPWQ2YW0
MoltNumber:      SOLR-47QD-GKWV-NPWQ-2YW0

Note: Same public key as Vector 1. The subscriber is completely

different because the nation code is included in the hash preimage.

B.3 Vector 3 (different key, same nation)

Nation Code:     MOLT
Public Key:      MCowBQYDK2VwAyEA5sL5FhLKBYNfSOg0mZ0TCp1etmM0xqUqYOKmz-zVZBo
SHA-256 Input:   MOLT:MCowBQYDK2VwAyEA5sL5FhLKBYNfSOg0mZ0TCp1etmM0xqUqYOKmz-zVZBo
SHA-256 Hex:     fce69cc464ff711332a35dd84dab4a0d68f774a68772b58b538f1a20084ee915
First 10 Bytes:  fce69cc464ff711332a3
Subscriber:      ZKK9SH34ZXRH6CN3
MoltNumber:      MOLT-ZKK9-SH34-ZXRH-6CN3

B.4 Verification of Test Vectors

For each vector:

  1. Call deriveSubscriber(nationCode, publicKey) and compare to the
expected subscriber.

  1. Call generateMoltNumber(nationCode, publicKey) and compare to the
expected full number.

  1. Call verifyMoltNumber(expectedNumber, publicKey) and confirm it
returns true.

  1. Call verifyMoltNumber(expectedNumber, differentPublicKey) and
confirm it returns false.

B.5 Cross-Nation Binding Assertion

Vectors 1 and 2 use the same public key but different nation codes.

Their MoltNumbers MUST differ:

MOLT-YQZZ-23ND-Q5KW-17VA  β‰   SOLR-47QD-GKWV-NPWQ-2YW0

This confirms that the nation code is cryptographically bound to the

subscriber β€” cross-nation impersonation is impossible.

B.6 Reference Implementation

The canonical reference implementation of the derivation algorithm is at

core/moltnumber/src/format.ts.

Implementors SHOULD validate their output against both these vectors and

the reference implementation.


Appendix C β€” Design Rationale

C.1 Why Self-Certifying?

Traditional phone numbers (E.164) require a carrier to vouch for

identity. SIM swaps, number portability, and carrier impersonation

undermine this model. A self-certifying number removes the carrier from

the trust chain for identity verification β€” the number IS the key.

C.2 Why 80 Bits?

80 bits balances human-friendliness against collision resistance:

BitsCharactersBirthday BoundAssessment
6012$\approx 10^{9}$Too small β€” brute-forceable
8016$\approx 10^{12}$Expensive but not infeasible
10020$\approx 10^{15}$Very safe, but less memorable
12826$\approx 10^{19}$Overkill for a routed number

80 bits was chosen as the sweet spot: the number fits on a business card

(24 characters total), is speakable in ~6 seconds, and the birthday

bound ($2^{40}$) requires substantial computation to attack. Carriers

provide an additional defense layer by enforcing first-seen binding.

C.3 Why Crockford Base32?

  • No ambiguous characters. I/1, O/0, L/1 confusion eliminated.
  • Case-insensitive. Uppercase canonical form, but input can be
lowercase.

  • URL-safe. No +, /, or = characters.
  • Compact. 5 bits per character vs. 4 bits for hex β€” 20% shorter
than hex for the same entropy.

  • Widely known. Well-documented by Douglas Crockford.

C.4 Why Include Nation in the Hash?

If the nation code were only a prefix (not included in the hash), an

attacker could take a number MOLT-AAAA-BBBB-CCCC-DDDD and claim

EVIL-AAAA-BBBB-CCCC-DDDD using the same public key. Including the

nation in the hash input means each nation produces a completely

different subscriber, making cross-nation impersonation impossible.

C.5 Why No Check Digit?

Traditional phone numbers use check digits (e.g., Luhn algorithm) to

catch transcription errors. MoltNumbers do not need this because:

  1. The hash IS the integrity check. A mistyped character will not match
any known public key.

  1. Check digits consume a character that could carry entropy.
  2. Verification against a public key is the authoritative test, not a
checksum.


_End of specification._