ZAP Protocol
Advanced Topics

W3C DID Support

Decentralized identity integration in ZAP

W3C DID Support

ZAP implements W3C Decentralized Identifiers (DIDs) for agent identity management.

Overview

DIDs provide:

  • Self-sovereign identity: Control your own identity
  • No central authority: Decentralized verification
  • Cryptographic binding: Identity tied to keys
  • Service discovery: Endpoints in DID documents

DID Methods

ZAP supports three DID methods:

enum DidMethod {
  lux @0;     # Lux blockchain-anchored DID
  key @1;     # Self-certifying DID from cryptographic key
  web @2;     # DNS-based DID
}

did:key

Self-certifying DIDs derived from public keys:

did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK
  • No blockchain required
  • Instant creation
  • Key is the identifier
  • Best for development/testing

did:lux

Blockchain-anchored DIDs on Lux Network:

did:lux:0x1234567890abcdef...
  • On-chain resolution
  • Updateable documents
  • Staking support
  • Best for production

did:web

DNS-based DIDs:

did:web:example.com
  • Resolved via HTTPS
  • Easy web integration
  • No blockchain needed
  • Good for organizations

DID Document

struct DidDocument {
  context @0 :List(Text);  # JSON-LD context
  id @1 :Text;             # DID subject
  controller @2 :Text;     # Optional controller DID

  # Verification methods (public keys)
  verificationMethod @3 :List(VerificationMethod);

  # Verification relationships
  authentication @4 :List(Text);
  assertionMethod @5 :List(Text);
  keyAgreement @6 :List(Text);
  capabilityInvocation @7 :List(Text);
  capabilityDelegation @8 :List(Text);

  # Service endpoints
  service @9 :List(Service);
}

Verification Methods

struct VerificationMethod {
  id @0 :Text;           # e.g., "did:lux:z6Mk...#keys-1"
  type @1 :VerificationMethodType;
  controller @2 :Text;   # Controller DID
  publicKeyMultibase @3 :Text;  # Multibase-encoded public key
  publicKeyJwk @4 :Data;        # JSON Web Key (optional)
  blockchainAccountId @5 :Text; # Blockchain account ID (for Lux)
}

enum VerificationMethodType {
  jsonWebKey2020 @0;
  multikey @1;
  mlDsa65VerificationKey2024 @2;  # Post-quantum
}

Services

struct Service {
  id @0 :Text;           # e.g., "did:lux:z6Mk...#zap-agent"
  type @1 :ServiceType;
  serviceEndpoint @2 :ServiceEndpoint;
}

enum ServiceType {
  zapAgent @0;           # ZAP Agent service
  didCommMessaging @1;   # DID Communication
  linkedDomains @2;      # Linked Domains
  credentialRegistry @3; # Credential Registry
}

DID Registry

interface DidRegistry {
  # Resolve a DID to its document
  resolve @0 (request :DidResolveRequest) -> (response :DidResolveResponse);

  # Create/register a new DID
  create @1 (request :DidCreateRequest) -> (response :DidCreateResponse);

  # Update a DID document (requires authentication)
  update @2 (did :Text, document :DidDocument, signature :Data) -> (success :Bool, error :Text);

  # Deactivate a DID (requires authentication)
  deactivate @3 (did :Text, signature :Data) -> (success :Bool, error :Text);

  # Get stake for a DID
  getStake @4 (did :Text) -> (amount :UInt64);

  # Set stake for a DID (requires authentication)
  setStake @5 (did :Text, amount :UInt64, signature :Data) -> (success :Bool, error :Text);
}

Usage Examples

Creating a DID

Rust

use zap_protocol::did::{Did, DidMethod, DidRegistry, Service, ServiceType};

// Generate ML-DSA keypair
let (public_key, private_key) = mldsa::generate_keypair();

// Connect to registry
let registry = DidRegistry::connect("zap://did-registry:9002").await?;

// Create did:key (instant, no blockchain)
let key_did = Did::new(DidMethod::Key, &public_key)?;
println!("Created: {}", key_did);  // did:key:z6Mk...

// Create did:lux (blockchain-anchored)
let lux_did = registry.create(
    DidMethod::Lux,
    &public_key,
    vec![
        Service {
            id: format!("{}#zap-agent", lux_did),
            service_type: ServiceType::ZapAgent,
            endpoint: "zap://my-agent.example.com:9000".into(),
        }
    ]
).await?;
println!("Created: {}", lux_did);  // did:lux:0x...

Go

import "github.com/zap-protocol/zap-go/did"

// Generate keypair
publicKey, privateKey := mldsa.GenerateKeypair()

// Connect to registry
registry, _ := did.ConnectRegistry(ctx, "zap://did-registry:9002")

// Create did:key
keyDID := did.New(did.MethodKey, publicKey)
fmt.Println("Created:", keyDID)

// Create did:lux
luxDID, _ := registry.Create(ctx, did.MethodLux, publicKey, []did.Service{
    {
        ID:       luxDID.String() + "#zap-agent",
        Type:     did.ServiceZapAgent,
        Endpoint: "zap://my-agent.example.com:9000",
    },
})

Resolving a DID

// Resolve any DID
let doc = registry.resolve("did:lux:0x1234...").await?;

println!("Controller: {}", doc.controller);
println!("Authentication keys: {:?}", doc.authentication);

// Find ZAP agent endpoint
for service in &doc.service {
    if service.service_type == ServiceType::ZapAgent {
        println!("Agent endpoint: {}", service.endpoint);
    }
}

Updating a DID Document

// Update document
let mut doc = registry.resolve(&did).await?;

// Add new service
doc.service.push(Service {
    id: format!("{}#new-service", did),
    service_type: ServiceType::LinkedDomains,
    endpoint: "https://example.com".into(),
});

// Sign and update
let signature = private_key.sign(&doc.serialize()?);
registry.update(&did, doc, signature).await?;

Node Identity

ZAP nodes use DIDs for identification:

struct NodeIdentity {
  did @0 :Did;
  publicKey @1 :Data;    # ML-DSA-65 public key (1952 bytes)
  stake @2 :UInt64;      # Staked amount (optional)
  stakeRegistry @3 :Text; # Stake registry reference
}

Creating Node Identity

use zap_protocol::did::NodeIdentity;

// Generate node identity
let node = NodeIdentity::generate()?;
node.save("./node-identity.key")?;

println!("Node DID: {}", node.did);
println!("Public key: {} bytes", node.public_key.len());

Staking

For Lux DIDs, staking is supported:

// Get current stake
let stake = registry.get_stake(&did).await?;
println!("Current stake: {}", stake);

// Increase stake
let signature = private_key.sign(&format!("stake:{}", new_amount));
registry.set_stake(&did, new_amount, signature).await?;

Stake affects:

  • Agent consensus voting weight
  • Ringtail party eligibility
  • Network priority

Security Considerations

  1. Key Storage: Use secure enclaves or HSMs
  2. Rotation: Plan for key rotation
  3. Recovery: Implement social recovery
  4. Deactivation: Deactivate compromised DIDs immediately

Best Practices

  1. Use did:key for development and testing
  2. Use did:lux for production with stake
  3. Include ZAP agent service endpoint in documents
  4. Register multiple verification methods
  5. Use ML-DSA-65 for post-quantum security

Last updated on

On this page