This document provides instructions for AI agents and human contributors working on the didwebvh-java project.
This is a Java 11+ library implementing the did:webvh v1.0 specification. It enables creating, resolving, updating, and deactivating did:webvh DIDs with pluggable key management.
- Simplicity over abstraction. A developer should be able to read through the codebase and understand it without tracing through many layers. Use design patterns only when they earn their keep (e.g., the
Signeradapter pattern, builders for log entry composition). - SOLID, but not academic. Single Responsibility and Dependency Inversion are key (the
Signerinterface is a good example). Don't create interfaces for things that will only ever have one implementation. - Java 11 baseline. No
varin public API. No records. No sealed classes. Use standard Java 11 features. Dependencies must also support Java 11. Newer JDKs may run the library, but code must remain Java 11-compatible. - Spec fidelity. The spec TXT (
docs/spec/Webvh v1.0.txt) is the source of truth. When in doubt, follow the spec literally. Reference spec section numbers in code comments for non-obvious logic. - Test-driven. Every public method must have tests. Spec-related logic (SCID generation, entry hash verification, log chain validation) must have tests against known test vectors.
didwebvh-java/
pom.xml # Parent POM (multi-module Maven)
didwebvh-core/ # Core library
pom.xml
src/main/java/io/github/decentralized-identity/didwebvh/
core/ # Top-level API (DidWebVh facade)
model/ # Data model (LogEntry, Parameters, DidDocument, etc.)
crypto/ # Hash, SCID, entry hash, JCS canonicalization
signing/ # Signer interface and proof generation
create/ # DID creation logic
resolve/ # DID resolution and log processing
update/ # DID update, migration, deactivation
validate/ # Log chain validation, witness verification
url/ # DID URL parsing and DID-to-HTTPS transformation
witness/ # Witness data model and proof handling
didweb/ # Parallel did:web document generation
src/test/java/...
src/test/resources/ # Test vectors (JSONL files, JSON files)
didwebvh-signing-local/ # Local JSON key file signer
pom.xml
src/main/java/io/github/decentralized-identity/didwebvh/signing/local/
LocalKeySigner.java
didwebvh-wizard/ # Interactive CLI
pom.xml
src/main/java/io/github/decentralized-identity/didwebvh/wizard/
WizardMain.java
CreateWizard.java
UpdateWizard.java
ResolveWizard.java
- Maven with multi-module layout. Parent POM manages dependency versions and plugin configuration.
- Maven Wrapper (
mvnw) is included so no local Maven install is required.
com.google.code.gson:gson- JSON parsing/serialization (widely used, Java 11 compatible)io.github.erdtman:java-json-canonicalization- JSON Canonicalization Scheme (JCS, RFC 8785)com.github.multiformats:java-multihash- Multihash encodingio.github.novacrypto:Base58- Base58btc encodingorg.bouncycastle:bcprov-jdk15on+bcpkix-jdk15on- Ed25519, cryptographic operations, Data Integrity proof signing/verificationcom.squareup.okhttp3:okhttp- HTTP client for DID resolution (optional, only in core for network resolution)
info.picocli:picocli- CLI frameworkorg.jline:jline- Interactive terminal input
org.junit.jupiter:junit-jupiter- JUnit 5org.assertj:assertj-core- Fluent assertionsorg.mockito:mockito-core- Mockingcom.squareup.okhttp3:mockwebserver- HTTP mocking for resolver tests
- Ed25519 via BouncyCastle for signing and verification (required by spec:
eddsa-jcs-2022cryptosuite) - SHA-256 for hashing (the only hash algorithm permitted by did:webvh:1.0)
- JCS (JSON Canonicalization Scheme, RFC 8785) for deterministic JSON serialization before hashing/signing
- Multihash for self-describing hash format
- Base58btc for encoding hashes and SCIDs
- Multikey format for public key representation in
updateKeys
public interface Signer {
/** Returns the key type string (e.g., "Ed25519"). */
String keyType();
/** Returns the verification method URI (e.g., "did:key:z6Mk...#z6Mk..."). */
String verificationMethod();
/** Signs the given data and returns the signature bytes. */
byte[] sign(byte[] data) throws SigningException;
}This is the primary extension point. Implementors can plug in:
- Local Ed25519 keys (provided by
didwebvh-signing-local) - AWS KMS (user implements
Signercalling AWS SDK) - External API (user implements
Signercalling their signing service) - HSM devices
The spec requires eddsa-jcs-2022 cryptosuite with proofPurpose: assertionMethod. The proof generation flow:
- JCS-canonicalize the log entry (without proof field)
- Sign the canonicalized bytes using the
Signer - Construct the
DataIntegrityProofobject withtype,cryptosuite,verificationMethod,proofPurpose,created,proofValue - Attach the proof to the log entry
Use builder pattern for CreateDidConfig and UpdateDidConfig so callers can compose their request step by step, then finalize with proof generation:
CreateDidResult result = DidWebVh.create("example.com")
.withSigner(signer)
.withPortable(true)
.withService("linked-domain", "https://example.com")
.execute();- No wildcard imports.
- No
@authortags. Use git blame. - Javadoc on all public classes and methods. One-liner is fine for getters.
- Package-private by default. Only expose what callers need.
- Immutable model classes where possible. Use builder or factory methods for construction.
- No checked exceptions in the public API. Wrap in
DidWebVhException(unchecked). - Null safety. Use
@Nullableannotation where nulls are expected. PreferOptionalfor return types that may be absent. Never accept null in public API methods without documenting it.
- JUnit 5 for all tests.
- Test vectors from the spec (JSONL files) must be included in
src/test/resources/test-vectors/. - Unit tests for each public class.
- Integration tests for end-to-end flows (create -> update -> resolve -> validate).
- Property-based tests are welcome but not required.
- Every PR must pass:
./mvnw clean verify - Use JDK 21 for local full verification. SpotBugs is skipped on JDK 22+ in this repository, so a local JDK 25 run can pass while the Java 11, 17, or 21 CI jobs fail on SpotBugs findings.
GitHub Actions workflows:
- ci.yml: Runs on every push to
mainand all PRs- Matrix build: Java 11, 17, 21, 25 on ubuntu-latest
./mvnw clean verify(compiles, tests, checks)- Code coverage via JaCoCo, uploaded to Codecov
- SonarCloud quality gate
- Checkstyle and SpotBugs static analysis. SpotBugs runs on Java 11, 17, and 21; it is skipped on Java 25 by the Maven profile for JDK 22+.
- release.yml: Triggered on version tag push, publishes to Maven Central via Sonatype
Use Conventional Commits:
feat: add DID creation with SCID generationfix: correct entry hash calculation for subsequent entriestest: add test vectors for log chain validationdocs: update README with resolve examplechore: configure JaCoCo for coverage reporting
- Read
docs/ARCHITECTURE.mdfor the full technical design. - Read
docs/dev/ITERATIONS.mdfor the ordered list of implementation tasks with detailed prompts. - Follow the iterations in order. Each iteration has clear acceptance criteria.
- Run
./mvnw clean verifywith JDK 21 after every change to ensure tests, Checkstyle, SpotBugs, and coverage run locally. - Keep dependencies minimal. Don't add a library for something that can be done in 20 lines.