An extended Python implementation of the Kademlia Distributed Hash Table, built on top of bmuller/kademlia, with native support for signed records and Verifiable Data Registry (VDR) capabilities for Decentralized Identifiers (DIDs).
A Rust reimplementation of this library is available at fratrung/AuthKademlia-RS. (WIP)
AuthKademlia extends the standard Kademlia protocol — an asynchronous, UDP-based DHT communicating via RPC over UDP and capable of operating behind NAT — with a cryptographic record layer that turns the network into a trustless, decentralized identity registry.
Unlike conventional DHT implementations, every value stored in the network is a verifiable artifact: cryptographically bound to its author and independently verifiable by any peer without relying on a central authority.
| Feature | Standard Kademlia | AuthKademlia |
|---|---|---|
| Record integrity | None | Cryptographic signature verification |
| Identity support | None | Native DID Document storage |
| Post-quantum cryptography | None | Dilithium & Kyber key support |
| Verifiable Data Registry | None | Built-in VDR semantics |
| NAT traversal | Yes | Yes |
pip install git+https://github.com/fratrung/AuthKademliaEach value stored in the DHT is a structured signed record with the following layout:
algorithm (12 bytes) | signature | DID Document (canonical JSON)
This structure allows any peer to:
- Verify the authenticity of stored data using the public key embedded in the DID Document
- Verify the integrity of the record against its signature
- Operate without trusting any single node or coordinator
- When inserting data (e.g., a DID Document), the record is digitally signed by the data owner using their private key.
- The DHT node validates the signature automatically via the integrated
DIDSignatureVerifierHandler. - Retrieved records can be independently verified by any node using the public key contained in the DID Document itself.
AuthKademlia is designed to interoperate with the did:iiot method, an open DID method targeting Industrial IoT environments.
DID Documents stored in the DHT embed post-quantum public keys (Dilithium for authentication, Kyber for key exchange), enabling:
- Secure device authentication
- Post-quantum key exchange
- Verifiable credential issuance and resolution
A complete end-to-end integration example is available at fratrung/did-iiot-dht.
The following example demonstrates how to generate post-quantum key pairs, construct a did:iiot DID Document, sign it, and store it as a verifiable record in the DHT.
import asyncio
from AuthKademlia.modules import Server, DilithiumKeyManager, KyberKeyManager, DIDSignatureVerifierHandler, Dilithium2
from did_iiot.modules import DIDIndustrialIoT, DIDDocument, Service, VerificationMethod
def base64_encode_publickey(pk: bytes) -> str:
"""Encodes a public key in base64url format (without padding)."""
return base64.urlsafe_b64encode(pk).decode('utf-8').rstrip("=")
def encode_did_document(did_document: dict) -> bytes:
"""Serializes a DID Document as canonical JSON bytes."""
return json.dumps(did_document, sort_keys=True, separators=(",", ":")).encode('utf-8')
def get_dilithium_pub_key_for_did_doc(did, pk, security_level, kid="k0"):
"""Creates a Dilithium public key JWK for inclusion in a DID Document."""
from did_iiot.did_iiot.publicjwk import DilithiumPublicJwkey
x = base64_encode_publickey(pk)
return DilithiumPublicJwkey(f"{did}#{kid}", security_level=security_level, x=x)
def get_kyber_pub_key_for_did_doc(did, pk, lat, kid="k1"):
"""Creates a Kyber public key JWK for inclusion in a DID Document."""
from did_iiot.did_iiot.publicjwk import KyberPublicJwkey
x = base64_encode_publickey(pk)
return KyberPublicJwkey(lat, x)
def get_signed_did_document_record(did_document: dict, sk: bytes, algorithm: str):
"""Signs the DID Document and returns a structured record (alg + signature + document)."""
raw_did_doc_encoded = encode_did_document(did_document)
alg = algorithm.encode('utf-8')[:12].ljust(12, b'\0')
signature = Dilithium2.sign(sk, raw_did_doc_encoded)
return alg + signature + raw_did_doc_encoded
async def run():
# Initialize DHT node with signature verification
node = Server(signature_verifier_handler=DIDSignatureVerifierHandler())
await node.listen(5678)
# Bootstrap to an existing DHT node
# Replace "127.0.0.1" and 5678 with a real bootstrap node address/port.
await node.bootstrap([("127.0.0.1", 5678)])
# NOTE: omit the bootstrap call if this is the first node in the network
# Generate post-quantum key pairs
dilith_mgr = DilithiumKeyManager("dilithium_keys")
kyber_mgr = KyberKeyManager("kyber_keys")
dilith_pk, dilith_sk = dilith_mgr.generate_keypair(2)
kyber_pk, kyber_sk = kyber_mgr.generate_keypair(512)
# Build the DID URI and DID Document
did = DIDIndustrialIoT.generate_did_uri()
dilith_jwk = get_dilithium_pub_key_for_did_doc(did, dilith_pk, 2)
kyber_jwk = get_kyber_pub_key_for_did_doc(did, kyber_pk, "Kyber-512", "k1")
vm_auth = VerificationMethod(f"{did}#k0", type="Authentication", public_jwkey=dilith_jwk)
vm_session = VerificationMethod(f"{did}#k1", type="KeySessionExchange", public_jwkey=kyber_jwk)
service = [Service(f"{did}#device", "DeviceAgent", "http://example.com/device")]
did_doc = DIDDocument(id=did, verification_methods=[vm_auth, vm_session], service=service)
# Sign and store the record in the DHT
signed_record = get_signed_did_document_record(did_doc.get_dict(), dilith_sk, algorithm="Dilithium-2")
key = did.split(":")[-1]
await node.set(key, signed_record)
# Retrieve and verify
result = await node.get(key)
print("Verified record:", result)
asyncio.run(run())AuthKademlia uses the standard Python logging library. To enable debug output to stdout:
import logging
log = logging.getLogger('kademlia')
log.setLevel(logging.DEBUG)
log.addHandler(logging.StreamHandler())- bmuller/kademlia — original Python Kademlia implementation this library extends
- AuthKademlia-RS — Rust reimplementation of this library
- did:iiot — DID method for Industrial IoT
- did-iiot-dht — end-to-end integration example