ma-core
A lean DIDComm service library for the ma ecosystem.
ma-core provides everything an ma endpoint needs: DID document publishing,
service inboxes, outbox delivery, and transport abstraction — without coupling
to any specific runtime or application.
What it provides
Messaging primitives
Inbox— bounded, TTL-aware FIFO receive queue for service endpoints. Per-message TTL is computed from each message'screated_at + ttl. Only endpoint implementations push to an inbox; consumers read viapop/peek/drain.Outbox— transport-agnostic write handle for fire-and-forget delivery. Takes aMessage, validates, serializes to CBOR, and transmits.
Service model
Servicetrait — declares a protocol identifier and label.MaEndpointtrait — shared interface for all transport endpoints: register services, get inboxes, send messages.IrohEndpoint(behindirohfeature) — iroh QUIC-backed implementation ofMaEndpoint.
Every endpoint must provide ma/inbox/0.0.1. Endpoints may optionally
provide ma/ipfs/0.0.1 to publish DID documents on behalf of others.
DID document publishing
validate_ipfs_publish_request— decodes a signed CBOR message, enforcesapplication/x-ma-ipfs-requestcontent type, validates the document, verifies sender matches IPNS identity.KuboDidPublisher(non-WASM,kubofeature) — publishes validated documents to IPFS via Kubo RPC.publish_did_document_to_kubo/handle_ipfs_publish— lower-level publish helpers.
Iroh startup metadata (ma.iroh)
When using iroh transport, update DID metadata from the live endpoint before publishing at startup:
let mut endpoint = new.await?;
// Optional service registrations here.
let _inbox = endpoint.service;
if endpoint.reconcile_document_ma_iroh?
DID resolution
DidResolvertrait — async DID-to-Document resolution.GatewayResolver— resolves via an IPFS/IPNS HTTP gateway.
Transport parsing
Parses DID document service strings like /iroh/<endpoint-id>/ma/inbox/0.0.1:
endpoint_id_from_transport/protocol_from_transportresolve_endpoint_for_protocol/resolve_inbox_endpoint_idtransport_string— build service strings from parts.
Identity bootstrap
generate_secret_key_file/load_secret_key_bytes— secure 32-byte key persistence with OS-level permission hardening.
Pinning
pin_update_add_rm— pin new CID, unpin old, report unpin failures as metadata (not hard errors).
Kubo RPC (non-WASM, kubo feature)
HTTP client for Kubo /api/v0/ endpoints: add, cat, DAG put/get,
IPNS publish/resolve, key management, pinning.
Feature flags
| Feature | Default | Description |
|---|---|---|
kubo |
no | Kubo RPC client for IPFS publishing |
iroh |
yes | Iroh QUIC transport (IrohEndpoint, Channel, Outbox) |
gossip |
yes | Iroh gossip helpers (join_gossip_topic, gossip_send, broadcast helpers) |
Platform support
Core types (Inbox, Service, transport parsing, validation)
compile on all targets including wasm32-unknown-unknown.
kuboAPIs are native-only.GatewayResolveris native-only.irohtransport compiles on wasm and native.gossipis optional and can be enabled when needed.
Quick usage
Consumers receive validated Message objects from an Inbox — the endpoint
handles deserialization and validation before messages enter the queue:
// Endpoint gives you an Inbox<Message> when you register a service
let mut inbox = endpoint.service;
let now = current_time_secs;
while let Some = inbox.pop
Example: full publish flow against Kubo (non-WASM):
async
End-to-end operational flow
This section shows a concrete non-WASM flow for publishing a DID document through Kubo.
1. Preconditions
- Kubo API is reachable at whichever base URL your environment uses.
- Create a publisher once with that URL and reuse the same instance.
- You have a signed CBOR
Messagepayload wherecontent_typeisapplication/x-ma-ipfs-request,fromis a DID whose IPNS id matches the DID document id, andcontentis JSON encodedIpfsPublishDidRequest. - The DID document is valid and signature-verifiable.
2. Validate and publish
Use KuboDidPublisher when you want a persisted endpoint configuration:
pub async
What it does internally:
validate_ipfs_publish_requestverifies message and document integrity.- Publisher imports the IPNS key under an ephemeral name, publishes, and removes the key immediately after.
- Returns
IpfsPublishDidResponsewithdidandcid.
3. Verify published target
After publish, resolve the IPNS name and compare to expected CID path:
pub async
4. Production readiness pattern
Recommended startup/publish order:
- create
KuboDidPublisher::new(kubo_url)once - call
publisher.wait_until_ready(attempts) - decode transport bytes
- call
publisher.publish_signed_message(...) - emit structured log with
did,cid - optionally run a post-publish
name_resolvecheck
Minimal orchestration example:
pub async
5. Failure semantics you should rely on
- Invalid CBOR, content type, DID document, or signatures fail fast.
- Sender/document IPNS mismatch fails fast.
- Missing/import-mismatched key material fails fast.
- IPNS publish uses retry and may still be accepted if resolve confirms target.
- Unpin failures in pin rotation are returned as metadata (
PinUpdateOutcome) and do not hide successful new pin operations.
Build and test
Wasm, slim iroh-only profile:
Wasm, iroh + gossip profile (when you need broadcast):
Run clippy when needed:
Design principles
- Strict input validation; never mutate malformed data.
- Small and clear building blocks, without unnecessary complexity.
- Shared types and contracts in the library; avoid duplication in consumers.
- Fail hard when identity, signature, or key mapping does not match.