Web of Trust Scenario
This document provides a complete walkthrough of using TrustWeave’s web of trust features, including trust registries, delegation chains, and proof purpose validation.
1
2
3
4
5
6
7
dependencies {
// TrustWeave distribution (includes all modules)
implementation("org.trustweave:distribution-all:1.0.0-SNAPSHOT")
// Test kit for in-memory implementations
testImplementation("org.trustweave:testkit:1.0.0-SNAPSHOT")
}
Result: These modules give you the trust-layer DSLs, registries, and in-memory mocks used throughout the walkthrough.
Overview
The web of trust scenario demonstrates how to:
- Set up trust anchors
- Issue trusted credentials
- Verify trust paths
- Delegate capabilities
- Verify delegation chains
- Use proof purpose validation
- Integrate all features together
Step-by-Step Walkthrough
Step 1: Configure Trust Layer with Trust Registry
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.trust.dsl.*
import java.time.Instant
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
val trustLayer = trustLayer {
keys {
provider(IN_MEMORY)
algorithm(ED25519)
}
did {
method(KEY) {
algorithm(ED25519)
}
}
credentials {
defaultProofType(ProofTypes.ED25519)
}
trust {
provider(IN_MEMORY)
}
}
}
What this does: Builds a trustLayer instance with in-memory KMS, DID method, credential defaults, and trust registry providers—perfect for local demos.
Outcome: Returns a configured trust layer you reuse in subsequent steps to create DIDs, issue credentials, and resolve trust anchors.
Step 2: Create DIDs for Entities
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.trustweave.trust.types.getOrThrowDid
val universityDid = trustLayer.createDid {
method(DidMethods.KEY)
algorithm(KeyAlgorithms.ED25519)
}.getOrThrowDid()
val companyDid = trustLayer.createDid {
method(DidMethods.KEY)
algorithm(KeyAlgorithms.ED25519)
}.getOrThrowDid()
val studentDid = trustLayer.createDid {
method(DidMethods.KEY)
algorithm(KeyAlgorithms.ED25519)
}.getOrThrowDid()
val hrDeptDid = trustLayer.createDid {
method(DidMethods.KEY)
algorithm(KeyAlgorithms.ED25519)
}.getOrThrowDid()
What this does: Issues four DIDs—university, company, student, and HR department—using the configured DID method.
Outcome: Each actor has a resolvable identifier that upcoming trust and delegation steps can reference.
Step 3: Set Up Trust Anchors
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
trustLayer.trust {
// Add university as trusted anchor for education credentials
addAnchor(universityDid) {
credentialTypes("EducationCredential", "DegreeCredential")
description("Trusted university for education credentials")
}
// Add company as trusted anchor for employment credentials
addAnchor(companyDid) {
credentialTypes("EmploymentCredential")
description("Trusted company for employment credentials")
}
// Verify trust anchors were added
val isUniversityTrusted = isTrusted(universityDid, "EducationCredential")
println("University trusted for EducationCredential: $isUniversityTrusted")
}
What this does: Seeds the trust registry with anchors for the university and company, then confirms the university anchor is active for education credentials.
Outcome: Subsequent verifications can rely on trust registry lookups instead of hard-coded issuer lists.
Step 4: Issue Credentials with Trust Verification
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
46
47
48
49
50
51
52
53
54
55
// Issue degree credential from university
import org.trustweave.trust.types.IssuanceResult
import org.trustweave.trust.types.getOrThrow
import org.trustweave.did.resolver.DidResolutionResult
import org.trustweave.did.identifiers.extractKeyId
// Helper extension for resolution results
fun DidResolutionResult.getOrThrow() = when (this) {
is DidResolutionResult.Success -> this.document
else -> throw IllegalStateException("Failed to resolve DID: ${this.errorMessage ?: "Unknown error"}")
}
// First, resolve university DID to get key ID
val universityDoc = trustLayer.resolveDid(universityDid).getOrThrow()
val universityKeyId = universityDoc.verificationMethod.firstOrNull()?.extractKeyId()
?: throw IllegalStateException("No verification method found")
val degreeCredential = trustLayer.issue {
credential {
id("https://university.edu/credentials/degree-123")
type(CredentialType.Education, CredentialType.Degree)
issuer(universityDid)
subject {
id(studentDid)
"degree" {
"type" to "Bachelor"
"field" to "Computer Science"
"university" to "Example University"
}
}
issued(Instant.now())
expires(Instant.now().plusSeconds(31536000)) // 1 year
}
signedBy(universityDid)
}.getOrThrow()
// Verify with trust registry
val verification = trustLayer.verify {
credential(degreeCredential)
checkTrustRegistry(true)
checkExpiration(true)
}
println("Verification Results:")
println(" Valid: ${verification.valid}")
println(" Trust Registry Valid: ${verification.trustRegistryValid}")
println(" Proof Valid: ${verification.proofValid}")
println(" Not Expired: ${verification.notExpired}")
if (verification.trustRegistryValid) {
println("✅ Issuer is trusted!")
} else {
println("❌ Issuer is not trusted")
}
What this does: Issues a degree credential and verifies it with trust registry and expiration checks enabled.
Outcome: A positive result confirms both the issuer’s trust anchor and the credential’s validity window are satisfied.
Step 5: Set Up Delegation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Company delegates credential issuance to HR department
trustLayer.updateDid {
did(companyDid)
method(DidMethods.KEY)
addCapabilityDelegation("$hrDeptDid#key-1")
}
// Verify delegation chain
val delegationResult = trustLayer.delegation {
verifyChain(delegatorDid = companyDid, delegateDid = hrDeptDid)
}
if (delegationResult.valid) {
println("✅ Delegation verified:")
println(" Path: ${delegationResult.path.joinToString(" -> ")}")
} else {
println("❌ Delegation failed:")
delegationResult.errors.forEach { println(" - $it") }
}
What this does: Adds capability delegation from the company to its HR department and validates the resulting delegation path.
Outcome: A valid result proves the HR department may act on behalf of the company when issuing credentials.
Step 6: Issue Credential Using Delegated Authority
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
// HR department issues credential using delegated authority
// First resolve HR DID to get key ID
val hrDoc = trustLayer.resolveDid(hrDeptDid).getOrThrow()
val hrKeyId = hrDoc.verificationMethod.firstOrNull()?.extractKeyId()
?: throw IllegalStateException("No verification method found")
import org.trustweave.trust.types.getOrThrow
val employmentIssuanceResult = trustLayer.issue {
credential {
id("https://company.com/credentials/employment-456")
type("EmploymentCredential")
issuer(hrDeptDid) // HR issues on behalf of company
subject {
id(studentDid)
"employment" {
"company" to "Tech Corp"
"role" to "Software Engineer"
"startDate" to "2024-01-01"
}
}
issued(Instant.now())
}
signedBy(hrDeptDid)
}
val employmentCredential = employmentIssuanceResult.getOrThrow()
// Verify credential with delegation check
val employmentVerification = trustLayer.verify {
credential(employmentCredential)
checkTrustRegistry(true)
verifyDelegation(true)
checkExpiration(true)
}
println("Employment Credential Verification:")
println(" Valid: ${employmentVerification.valid}")
println(" Trust Registry Valid: ${employmentVerification.trustRegistryValid}")
println(" Delegation Valid: ${employmentVerification.delegationValid}")
What this does: Issues an employment credential from the delegated HR DID and verifies it with both trust registry and delegation checks enabled.
Outcome: Successful verification confirms the delegation chain and trust anchors are respected before the credential is accepted.
Step 7: Find Trust Paths
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
trustLayer.trust {
// Get all trusted issuers for a credential type
val educationIssuers = getTrustedIssuers("EducationCredential")
println("Trusted education issuers: ${educationIssuers.joinToString(", ")}")
// Find trust path between two DIDs (if trust relationships exist)
val trustPath = getTrustPath(universityDid, companyDid)
if (trustPath != null) {
println("Trust path found:")
println(" Path: ${trustPath.path.joinToString(" -> ")}")
println(" Trust Score: ${trustPath.trustScore}")
println(" Valid: ${trustPath.valid}")
} else {
println("No trust path found between university and company")
}
}
What this does: Lists all trusted issuers for education credentials and attempts to compute a trust path between the university and company anchors.
Outcome: If a path exists you receive the ordered DIDs and trust score, helping you diagnose trust relationships before accepting credentials.
Step 8: Update DID Documents with New Fields
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
trustLayer.updateDid {
did(studentDid)
method(DidMethods.KEY)
// Add capability invocation for signing documents
addCapabilityInvocation("$studentDid#key-1")
// Add capability delegation for delegating to assistants
addCapabilityDelegation("$studentDid#key-2")
// Set JSON-LD context
context("https://www.w3.org/ns/did/v1", "https://example.com/context/v1")
}
println("✅ DID document updated with capability relationships and context")
What this does: Augments the student DID document with capability invocation/delegation relationships and an expanded JSON-LD context.
Outcome: The student can now sign documents and delegate capabilities while verifiers understand the DID document structure.
Step 9: Use Proof Purpose Validation
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Update issuer DID to have assertionMethod relationship
trustLayer.updateDid {
did(universityDid)
method(DidMethods.KEY)
addAssertionMethod("$universityDid#key-1")
}
// Issue credential with assertionMethod proof purpose
import org.trustweave.trust.types.getOrThrow
val validatedIssuanceResult = trustLayer.issue {
credential {
id("https://university.edu/credentials/validated-789")
type("EducationCredential")
issuer(universityDid)
subject {
id(studentDid)
"certification" {
"name" to "Certified Developer"
"level" to "Advanced"
}
}
issued(Instant.now())
}
signedBy(universityDid)
proofPurpose(ProofPurposes.ASSERTION_METHOD)
}
val validatedCredential = validatedIssuanceResult.getOrThrow()
// Verify with proof purpose validation
val proofPurposeVerification = trustLayer.verify {
credential(validatedCredential)
validateProofPurpose(true)
checkTrustRegistry(true)
}
println("Proof Purpose Validation:")
println(" Valid: ${proofPurposeVerification.valid}")
println(" Proof Purpose Valid: ${proofPurposeVerification.proofPurposeValid}")
println(" Trust Registry Valid: ${proofPurposeVerification.trustRegistryValid}")
**What this does:** Ensures the issuer’s DID advertises `assertionMethod`, issues a credential with that proof purpose, and validates the proof purpose alongside trust and expiration checks.
**Outcome:** A `proofPurposeValid` flag of `true` confirms the credential’s proof aligns with the declared purpose, preventing misuse in other contexts.
### Step 10: Complete Integration Example
```kotlin
// Complete workflow combining all features
fun completeWebOfTrustWorkflow() = runBlocking {
val trustLayer = trustLayer {
keys { provider(IN_MEMORY) }
did { method(DidMethods.KEY) }
trust { provider(IN_MEMORY) }
}
// 1. Create DIDs
import org.trustweave.trust.types.getOrThrowDid
val issuerDid = trustLayer.createDid { method(DidMethods.KEY) }.getOrThrowDid()
val holderDid = trustLayer.createDid { method(DidMethods.KEY) }.getOrThrowDid()
// 2. Set up trust anchor
trustLayer.trust {
addAnchor(issuerDid.value) {
credentialTypes("TestCredential")
}
}
// 3. Update issuer DID with assertionMethod
val updateResult = trustLayer.updateDid {
did(issuerDid.value)
method(DidMethods.KEY)
addAssertionMethod("${issuerDid.value}#key-1")
}
when (updateResult) {
is DidUpdateResult.Success -> { /* Success */ }
else -> throw IllegalStateException("Failed to update DID: ${updateResult.reason}")
}
// 4. Resolve issuer DID to get key ID
val issuerDoc = trustLayer.resolveDid(issuerDid).getOrThrow()
val issuerKeyId = issuerDoc.verificationMethod.firstOrNull()?.extractKeyId()
?: throw IllegalStateException("No verification method found")
// 5. Issue credential
import org.trustweave.trust.types.getOrThrow
val credential = trustLayer.issue {
credential {
id("https://example.com/credential-1")
type("TestCredential")
issuer(issuerDid)
subject {
id(holderDid.value)
"test" to "value"
}
issued(Instant.now())
}
signedBy(issuerDid)
proofPurpose(ProofPurposes.ASSERTION_METHOD)
}.getOrThrow()
// 6. Verify with all checks enabled
val result = trustLayer.verify {
credential(credential)
checkTrustRegistry(true)
validateProofPurpose(true)
checkExpiration(true)
}
// 7. Check results
println("Complete Verification Results:")
println(" Valid: ${result.valid}")
println(" Trust Registry Valid: ${result.trustRegistryValid}")
println(" Proof Purpose Valid: ${result.proofPurposeValid}")
println(" Proof Valid: ${result.proofValid}")
println(" Not Expired: ${result.notExpired}")
if (result.valid && result.trustRegistryValid && result.proofPurposeValid) {
println("✅ Credential verified successfully with all checks!")
}
}
What this does: Demonstrates the full trust workflow in miniature—build a trust layer, establish anchors, issue a credential with proof purpose, and verify it with all checks enabled.
Outcome: Use this function as a regression test to ensure future changes preserve the trust-layer guarantees.
Real-World Use Cases
University Credential Verification
Universities can be added as trust anchors, allowing verifiers to automatically trust credentials issued by recognized institutions.
1
2
3
4
5
6
trustLayer.trust {
addAnchor(universityDid) {
credentialTypes("EducationCredential", "DegreeCredential", "CertificateCredential")
description("Accredited university")
}
}
Outcome: Any verifier consulting the trust registry now recognises the university’s credentials automatically, reducing ad-hoc whitelists across institutions.
Corporate Delegation
Companies can delegate credential issuance to HR departments, creating a hierarchical authority structure while maintaining centralized trust.
1
2
3
4
5
6
7
8
9
10
11
// CEO delegates to HR Director
trustLayer.updateDid {
did(ceoDid)
addCapabilityDelegation("$hrDirectorDid#key-1")
}
// HR Director delegates to HR Manager
trustLayer.updateDid {
did(hrDirectorDid)
addCapabilityDelegation("$hrManagerDid#key-1")
}
Outcome: A delegation ladder forms so HR staff can issue credentials while the executive team retains ultimate control over capability revocation.
Multi-Party Trust Networks
Multiple organizations can form trust networks where credentials issued by one trusted party are automatically trusted by others in the network.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create trust network
trustLayer.trust {
addAnchor(organization1Did) {
credentialTypes("PartnershipCredential")
}
addAnchor(organization2Did) {
credentialTypes("PartnershipCredential")
}
addAnchor(organization3Did) {
credentialTypes("PartnershipCredential")
}
// Get all trusted partners
val partners = getTrustedIssuers("PartnershipCredential")
println("Trusted partners: ${partners.joinToString(", ")}")
}
Outcome: A single query returns every organisation trusted for partnership credentials, making it easy to surface network relationships to auditors or dashboards.
Best Practices
- Use Credential Type Filtering: Specify credential types when adding trust anchors to limit trust scope
- Verify Delegation Chains: Always verify delegation chains when accepting delegated credentials
- Check Trust Paths: Verify trust paths before accepting credentials from unknown issuers
- Update DID Documents: Keep DID documents up-to-date with capability relationships
- Use Proof Purpose Validation: Enable proof purpose validation to ensure proofs are used correctly
- Monitor Trust Scores: Use trust scores to make informed decisions about credential acceptance
- Regular Audits: Periodically review and update trust anchors and delegation relationships
Error Handling
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try {
val result = trustLayer.verify {
credential(credential)
checkTrustRegistry(true)
validateProofPurpose(true)
verifyDelegation(true)
}
if (!result.valid) {
println("Verification failed:")
result.errors.forEach { println(" - $it") }
result.warnings.forEach { println(" Warning: $it") }
}
} catch (e: Exception) {
println("Verification error: ${e.message}")
}
Outcome: Errors and warnings are surfaced explicitly so you can distinguish hard failures (invalid proofs, missing trust anchors) from advisory messages during troubleshooting.