trustweave-did (Core Module)

The trustweave-did module provides Decentralized Identifier (DID) and DID Document management with support for pluggable DID methods, DID resolution, and DID registration interfaces.

1
2
3
4
5
dependencies {
    implementation("org.trustweave:trustweave-did:1.0.0-SNAPSHOT")
    implementation("org.trustweave:trustweave-common:1.0.0-SNAPSHOT")
    implementation("org.trustweave:trustweave-kms:1.0.0-SNAPSHOT")
}

Result: Gradle exposes the DID registry, DID method interfaces, DID Document models, DID resolution, and DID registration interfaces so you can create, resolve, update, and deactivate DIDs using any supported DID method.

Overview

The trustweave-did core module provides:

  • DidMethod Interface – contract for DID method implementations
  • DID Document Models – W3C-compliant DID Document structures
  • DidMethodRegistry – instance-scoped registry for managing DID methods
  • DID Resolution – unified interface for resolving DIDs across methods
  • DID Registration – interfaces and models for DID registration operations
  • DID Operations – create, resolve, update, and deactivate operations
  • SPI Support – service provider interface for auto-discovery of DID method implementations
  • JSON Registration – support for loading DID methods from JSON configuration files

Architecture

graph TB
    subgraph "trustweave-did Core Module"
        DidMethod[DidMethod Interface]
        DidMethodRegistry[DidMethodRegistry]
        DidResolver[DidResolver]
        DidRegistrar[DidRegistrar Interface]
        DidDocument[DidDocument Models]
        DidValidator[DidValidator]
    end

    subgraph "DID Method Implementations"
        KeyMethod[did:key]
        WebMethod[did:web]
        EthrMethod[did:ethr]
        IonMethod[did:ion]
        HttpMethod[HttpDidMethod]
    end

    subgraph "External Services"
        UniversalResolver[Universal Resolver]
        UniversalRegistrar[Universal Registrar]
    end

    DidMethod --> DidMethodRegistry
    DidMethodRegistry --> DidResolver
    DidMethod --> DidRegistrar
    DidResolver --> UniversalResolver
    HttpMethod --> UniversalResolver
    HttpMethod --> UniversalRegistrar
    DidRegistrar --> UniversalRegistrar

    style DidMethod fill:#e1f5ff
    style DidMethodRegistry fill:#e1f5ff
    style DidResolver fill:#e1f5ff
    style DidRegistrar fill:#e1f5ff

Key Components

DidMethod Interface

1
2
3
4
5
6
7
8
9
10
11
import org.trustweave.did.*
import org.trustweave.did.identifiers.Did

interface DidMethod {
    val method: String  // e.g., "key", "web", "ion"

    suspend fun createDid(options: DidCreationOptions): DidDocument
    suspend fun resolveDid(did: Did): DidResolutionResult
    suspend fun updateDid(did: Did, updater: (DidDocument) -> DidDocument): DidDocument
    suspend fun deactivateDid(did: Did): Boolean
}

What this does: Defines the contract for DID operations that all DID method implementations must fulfill.

Outcome: Enables TrustWeave to support multiple DID methods (key, web, ethr, ion, etc.) through a unified interface.

DidMethodRegistry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Manual registration
val registry = DidMethodRegistry()
registry.register(keyDidMethod)
registry.register(webDidMethod)

// Auto-register from SPI providers
val registry = DidMethodRegistry.autoRegister(kms)

// Access methods
val method = registry["key"]  // Using bracket notation
val didDoc = method?.createDid(options)

// Idiomatic Kotlin API with builder DSL
val registry = didMethodRegistry {
    register(KeyDidMethod(kms))
    register(WebDidMethod())
}

// Operator overloads
val method = registry["key"]  // Bracket notation
if ("key" in registry) {     // `in` operator
    // Method is registered
}
registry["new"] = NewDidMethod()  // Assignment

What this does: Provides instance-scoped registration and retrieval of DID methods. Supports both manual registration and automatic discovery via Service Provider Interface (SPI). All operations are thread-safe.

Outcome: Allows multiple DID methods to coexist in the same application context with improved developer experience.

DidResolver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.trustweave.did.identifiers.Did
import org.trustweave.did.resolver.RegistryBasedResolver
import org.trustweave.did.resolver.DefaultUniversalResolver

// Registry-based resolver
val resolver = RegistryBasedResolver(registry)
val did = Did("did:key:z6Mk...")
val result = resolver.resolve(did)

// Universal Resolver with retry logic
val universalResolver = DefaultUniversalResolver(
    baseUrl = "https://dev.uniresolver.io",
    retryConfig = RetryConfig.default()
)
val result2 = universalResolver.resolveDid(did.value)

// Fluent API with extensions
val document = did.resolveWith(resolver).getOrThrow()
val docOrNull = did.resolveOrNull(resolver)
val docOrDefault = did.resolveOrDefault(resolver, defaultDocument)

What this does: Provides a unified interface for resolving DIDs across different methods with automatic retry and fluent API support.

Outcome: Enables method-agnostic DID resolution with proper error handling, resilience, and improved developer experience.

DidRegistrar Interface

1
2
3
4
5
6
7
import org.trustweave.did.registrar.*

interface DidRegistrar {
    suspend fun createDid(method: String, options: CreateDidOptions): DidRegistrationResponse
    suspend fun updateDid(did: String, document: DidDocument, options: UpdateDidOptions): DidRegistrationResponse
    suspend fun deactivateDid(did: String, options: DeactivateDidOptions): DidRegistrationResponse
}

What this does: Defines the contract for DID registration operations according to the DID Registration specification.

Outcome: Enables method-agnostic DID creation, updates, and deactivation through registrar services.

Note: The DidRegistrar interface is defined in the core module, but implementations are provided in the trustweave-did-registrar module. See DID Registrar Module for implementation details.

DID Document Models

The module includes W3C-compliant models for:

  • DidDocument – complete DID Document structure
  • VerificationMethod – public key and verification methods
  • DidService – service endpoints
  • DidResolutionResult – resolution response with metadata
  • DidRegistrationResponse – registration response with job tracking
  • DidState – operation state (finished, failed, action, wait)
  • Secret – key material for registration operations

What this does: Provides type-safe, serializable models for DID documents that comply with W3C DID Core specification and DID Registration specification.

Outcome: Ensures interoperability with other DID implementations and proper serialization.

JSON-Based DID Method Registration

The module supports loading DID methods from JSON configuration files that follow the DID Method Registry format:

1
2
3
val loader = JsonDidMethodLoader()
val method = loader.loadFromFile(Paths.get("did-methods/web.json"))
registry.register(method)

What this does: Enables DID methods to be registered without writing code, using JSON configuration files.

Outcome: Simplifies adding support for new DID methods by providing configuration-driven registration.

See DID Registration Integration Guide for detailed information.

Component Relationships

graph LR
    subgraph "Core Interfaces"
        DM[DidMethod]
        DR[DidRegistrar]
        DRes[DidResolver]
    end

    subgraph "Registry & Resolution"
        DMR[DidMethodRegistry]
        RBR[RegistryBasedResolver]
        DUR[DefaultUniversalResolver]
    end

    subgraph "Registration Models"
        CRO[CreateDidOptions]
        URO[UpdateDidOptions]
        DRO[DeactivateDidOptions]
        DRR[DidRegistrationResponse]
        DS[DidState]
    end

    subgraph "Document Models"
        DD[DidDocument]
        VM[VerificationMethod]
        DSvc[DidService]
    end

    DM --> DMR
    DMR --> RBR
    RBR --> DRes
    DR --> DRR
    DRR --> DS
    DM --> DD
    DD --> VM
    DD --> DSvc
    DR --> CRO
    DR --> URO
    DR --> DRO

    style DM fill:#e1f5ff
    style DR fill:#e1f5ff
    style DRes fill:#e1f5ff

Usage Examples

Basic Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import org.trustweave.TrustWeave
import org.trustweave.did.*
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    // Create TrustWeave instance with DID methods
    val trustweave = TrustWeave.create {
        didMethods {
            + DidKeyMethod(kms)  // Register did:key method
        }
    }

    // Create DID with options
    val didDoc = trustweave.dids.create("key") {
        algorithm = KeyAlgorithm.Ed25519
    }

    println("Created DID: ${didDoc.id}")

    // Resolve DID
    val resolution = trustweave.dids.resolve(didDoc.id)
    if (resolution.document != null) {
        println("Resolved DID: ${resolution.document.id}")
    } else {
        println("DID not found: ${resolution.resolutionMetadata["error"]}")
    }
}

What this does: Uses SPI to discover a DID method provider, creates a DID using the did:key method, and then resolves it.

Outcome: Enables seamless DID operations across different DID methods.

Idiomatic Kotlin API

The module provides a fluent, idiomatic Kotlin API with builder DSLs, extension functions, and operator overloads:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import org.trustweave.did.identifiers.Did
import org.trustweave.did.resolver.universalResolver
import org.trustweave.did.registry.didMethodRegistry
import org.trustweave.did.resolver.RegistryBasedResolver

// Builder DSL for resolver with retry configuration
val resolver = universalResolver("https://dev.uniresolver.io") {
    timeout = 60
    apiKey = "my-api-key"
    retry {
        maxRetries = 3
        initialDelayMs = 200
        maxDelayMs = 2000
    }
}

// Builder DSL for registry
val registry = didMethodRegistry {
    register(KeyDidMethod(kms))
    register(WebDidMethod())
    registerAll(OtherMethod1(), OtherMethod2())
}

// Operator overloads for registry
val method = registry["key"]  // Bracket notation
if ("key" in registry) {      // `in` operator
    // Method is registered
}
registry["new"] = NewDidMethod()  // Assignment

// Fluent resolution with extensions
val document = Did("did:key:123")
    .resolveWith(resolver)
    .getOrThrow()

// Or with safe access
val doc = Did("did:key:123")
    .resolveWith(resolver)
    .getOrNull()

// Functional style with callbacks
Did("did:key:123")
    .resolveWith(resolver)
    .onSuccess { println("Resolved: ${it.id}") }
    .onFailure { println("Failed: ${it.reason}") }

What this does: Provides a modern, fluent API that leverages Kotlin’s language features for better developer experience.

Outcome: More readable, maintainable code with better error handling and type safety.

Retry Logic and Resilience

The module includes automatic retry logic with exponential backoff for HTTP operations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import org.trustweave.did.resolver.DefaultUniversalResolver
import org.trustweave.did.resolver.RetryConfig

// Default retry configuration (3 retries, 100ms initial delay)
val resolver = DefaultUniversalResolver(
    baseUrl = "https://dev.uniresolver.io",
    retryConfig = RetryConfig.default()
)

// Aggressive retry for unreliable networks
val aggressiveResolver = DefaultUniversalResolver(
    baseUrl = "https://dev.uniresolver.io",
    retryConfig = RetryConfig.aggressive()  // 5 retries, 200ms initial delay
)

// Custom retry configuration
val customRetry = RetryConfig(
    maxRetries = 5,
    initialDelayMs = 200,
    maxDelayMs = 5000,
    retryableStatusCodes = setOf(500, 502, 503, 504),
    retryableExceptions = setOf(
        java.net.ConnectException::class.java,
        java.net.SocketTimeoutException::class.java
    )
)
val customResolver = DefaultUniversalResolver(
    baseUrl = "https://dev.uniresolver.io",
    retryConfig = customRetry
)

What this does: Automatically retries transient failures (network errors, 5xx HTTP errors) with exponential backoff and jitter.

Outcome: Improved reliability and resilience for production deployments.

Supported DID Methods

TrustWeave provides implementations for:

Additionally, the module supports HTTP-based DID methods through JSON configuration. See DID Registration Integration Guide for details.

Module Structure

graph TD
    subgraph "did:did-core Package Structure"
        A[org.trustweave.did]
        A --> B[DidMethod.kt]
        A --> C[DidCreationOptions.kt]
        A --> D[model/]
        A --> E[registry/]
        A --> F[resolver/]
        A --> G[registrar/]
        A --> H[registration/]
        A --> I[validation/]
        A --> J[spi/]

        D --> D1[DidModels.kt]
        E --> E1[DidMethodRegistry.kt]
        F --> F1[DidResolver.kt]
        F --> F2[RegistryBasedResolver.kt]
        F --> F3[UniversalResolver.kt]
        G --> G1[DidRegistrar.kt]
        G --> G2[model/]
        H --> H1[loader/]
        H --> H2[impl/]
        H --> H3[mapper/]
    end

    style A fill:#e1f5ff
    style G fill:#fff4e1
    style H fill:#e8f5e9

Key Features

Performance Optimizations

  • Cached Validation: Base URL validation is cached during initialization, eliminating redundant validation overhead
  • Efficient Parsing: Optimized string operations for DID parsing with lazy initialization
  • Thread Safety: ConcurrentHashMap-based registry for thread-safe operations without explicit locks

Resilience Features

  • Automatic Retry: Exponential backoff with jitter for transient failures
  • Configurable Retry: Customizable retry policies for different network conditions
  • Error Recovery: Structured error handling with detailed context

Developer Experience

  • Builder DSLs: Fluent API for resolver and registry configuration
  • Extension Functions: Functional-style operations for common tasks
  • Operator Overloads: Intuitive API with bracket notation and in operator
  • Type Safety: Strong typing throughout with sealed classes for exhaustive handling

Dependencies

Next Steps


This site uses Just the Docs, a documentation theme for Jekyll.