Experimental
, inspired byipfs
, andkeri
See also (related topics):
Alice
has a secret message forBob
, but she doesn’t know whoBob
is or where he is.
DIDs and DIDComm address this challenge by providing decentralized identifiers with built‐in service endpoints and mediator support. This allows Alice to discover Bob’s DID and send her message securely.
KERI (Key Event Receipt Infrastructure) further strengthens the system by managing identities in a truly decentralized, ledger-independent way. It uses secure, self‑sovereign keys and event-based updates to maintain identity integrity.
While DIDs, DIDComm, and KERI provide a robust framework for decentralized messaging and identity management, several challenges remain to fully realize a seamless self‑sovereign identity ecosystem. Addressing these challenges is essential for ensuring reliable identity resolution, efficient communication, and long‑term protocol evolution. The key challenges include:
How to reliably resolve a decentralized identifier.
How to efficiently notify subscribers about KERI events.
How to know communication locations send messages to one or more subscribers.
How to manage identity protocol changes and support multiple implementations.
This overview lays the groundwork for addressing these challenges within a self-sovereign identity ecosystem.
Peer to peer identity protocol based on keri, webassembly and libp2p
idp2p is a decentralized identity protocol that leverages peer-to-peer networks to enable secure and efficient identity discovery, notification, and messaging. It combines a pubsub (libp2p gossipsub) model with KERI
in order to solve the challenges.
In idp2p, each DID is represented as a dedicated pub/sub topic on the libp2p network, unifying discovery and messaging in a single mechanism—by subscribing to a DID’s topic, peers discover identities, learn and update service endpoints, and exchange both direct and broadcast messages in a decentralized manner.
KERI implementation with webassembly
Model of the identity layer(webassembly interface types):
package idp2p:id;
world idp2p-id {
record id-version {
major: u16,
minor: u16
}
/// Cryptographic proof attached to identity events to verify authenticity.
record persisted-id-proof {
id: string, // Identifier of the public key
pk: list<u8>, // Public key used to verify the signature
sig: list<u8>, // Cryptographic signature proving authenticity
}
/// Represents the initial creation event (inception) of an identity.
record persisted-id-inception {
id: string, // Unique identifier for the new identity
version: u32, // Version number of the inception data format
payload: list<u8>, // Raw binary payload containing inception data
}
/// Represents subsequent events or updates related to an existing identity.
record persisted-id-event {
id: string, // Identifier of this event
version: u32, // Version number of the event data format
payload: list<u8>, // Binary payload describing the event
proofs: list<persisted-id-proof>, // List of cryptographic proofs verifying event authenticity
}
/// Represents the authoritative current state or snapshot of an identity.
record id-state {
version: u32, // Version number of the identity state format
payload: list<u8>, // Raw binary payload representing identity state data
}
/// Represents a claim or attribute associated with an identity, possibly updated over time.
record id-claim {
key: string, // Key identifying the specific claim or attribute
payload: list<u8>, // Binary payload containing the claim data
}
/// Successful result structure returned after verifying identity inception or events.
record id-result {
state: id-state, // The verified identity state after the operation
claims: list<id-claim>, // Collection of verified claims associated with the identity
}
/// Verifies an initial identity inception event.
export verify-inception: func(incepiton: persisted-id-inception) -> result<id-result, string>;
/// Verifies an identity update event against the existing identity state.
export verify-event: func(state: id-state, event: persisted-id-event) -> result<id-result, string>;
}
Based on libp2p gossipsub protocol
Alice wants to resolve Bob’s ID
Alice Publishes a Resolve
Message
Alice begins by publishing a Resolve
message onto the network. This message includes Bob’s ID as the topic she wants to resolve.
Bob Publishes a Provide
Message
Upon noticing that there is a Resolve
request for his ID, Bob publishes a Provide
message with the same topic (Bob’s ID). This message specifies a list of peers (called “provider peers”) who can supply the necessary identity information.
Alice Requests Bob’s Identity from a Provider Peer
After receiving Bob’s Provide
message, Alice selects one of the provider peers and sends a direct request, asking for Bob’s identity data.
Provider Peer Sends Response
The selected provider peer responds by sending Bob’s identity information to Alice.
Alice Verifies and Stores Bob’s Identity
Once the response is received, Alice verifies the authenticity of Bob’s identity data. Upon successful verification, she stores Bob’s identity for future reference.
sequenceDiagram
participant Alice
participant ProviderPeer
participant P2PNet as P2P Network
participant Bob
Alice->>P2PNet: Publish `Resolve` (topic = Bob's ID)
Bob->>P2PNet: Publish `Provide` (topic = Bob's ID, providers)
Alice->>ProviderPeer: Request Bob's identity
ProviderPeer->>Alice: Return Bob's identity data
Alice->>Alice: Verify authenticity & store Bob's identity
Alice has an keri event and she wants to notify her subscribers
Identity Owner Publishes Event
Alice, acting as the identity owner, generates a KERI event and publishes it to the network using her own ID as the topic.
Network Notifies Subscribers
The P2P network delivers the event to Alice’s subscribers.
Subscriber Verifies and Stores Event
Upon receiving the event, each subscriber verifies the event’s integrity/authenticity and, if valid, stores the event locally.
sequenceDiagram
participant Alice as Alice (Identity Owner)
participant P2P as P2P Network
participant Subscriber as Subscriber
Alice->>P2P: Publish KERI event (topic = Alice's ID)
P2P->>Subscriber: Notify event
Subscriber->>Subscriber: Verify event
Subscriber->>Subscriber: Store event
Alice wants to send a message to Bob
Message
Message
onto the network with:
Bob Notices the New Message
The P2P network (or whichever messaging infrastructure is used) notifies Bob that there is a new message for him (identified by the Message ID
).
Bob Requests the Message
Bob sends a request to one of the listed provider peers to fetch the actual message content.
sequenceDiagram
participant Alice
participant ProviderPeer
participant P2PNet as P2P Network
participant Bob
Alice->>P2PNet: Publish `Message` (topic = Bob's ID, message ID, provider peers)
P2PNet->>Bob: Notify new `Message` (message ID)
Bob->>ProviderPeer: Request message (using message ID)
ProviderPeer->>Bob: Send message content
Alice wants to publish for all subsribers
Network Notifies All Subscribers
Any subscriber that is subscribed to Alice’s ID receives a notification about the new broadcast message.
Subscribers Request the Broadcast Message
Each subscriber selects a provider peer and requests the message content using the Message ID
.
In this protocol, messaging is not tied to a location-based address. Instead, the recipient’s ID itself serves as the address. Consequently, the idp2p service does not require a dedicated endpoint.
Messages are encrypted in transit using the built-in libp2p TLS layer. No additional encryption mechanism is provided by the protocol itself.
When a message is sent to a specific ID, hash of the message and provider node details are published via pubsub. Recipients then fetch the full message from the provider nodes.
The idp2p protocol and implementations are both work in progress.
Contributions are most welcome.