Architecture Deep Dive

Read this before touching the crypto layer or the verification path.

Required reading

Before making changes to the core verification logic:

  1. docs/Drs_language&algorithms.md — authoritative reference for language choices and corrected algorithms
  2. docs/drs-source-of-truth.md — current implementation contract
  3. False Positives: What We Tried — the v1 and v2 failures

docs/Drs_architecture_v2.md is still useful, but as a historical prior-working-path document rather than the live implementation spec.

Module boundaries

Each module has exactly one responsibility. Do not write code that crosses these boundaries:

ModuleResponsibilityDoes NOT do
drs-core/src/crypto/Ed25519 sign/verify, SHA-256JWT parsing, policy evaluation
drs-core/src/chain/Chain hash computation, verify_chainNetwork I/O, caching
drs-core/src/jcs/RFC 8785 canonicalisationSerialisation to non-JSON formats
drs-core/src/capability/Policy evaluation, attenuation checkCrypto operations
drs-core/src/did/did:key decode to public key bytesDID resolution with caching
drs-verify/pkg/resolver/DID resolution + LRU cacheChain verification
drs-verify/pkg/verify/verify_chain (6 blocks)DID resolution, HTTP I/O
drs-verify/pkg/middleware/HTTP request/response handlingVerification logic
drs-verify/pkg/policy/Policy field evaluationSigning, serialisation
drs-sdk/src/sdk/Issuance (sign + build JWTs)Verification
drs-sdk/src/verify/HTTP client to drs-verifyVerification logic itself
drs-sdk/src/cli/CLI command dispatchSDK logic

Data flow

Issuance (TypeScript SDK):
  Policy params → jcsSerialise(payload) → sign → JWT string

Verification (Go):
  JWT string → parse header/payload → resolve_did → crypto/ed25519.Verify
            → check_policy_attenuation → revocation checks → VerificationResult

DID resolution (Go):
  DID string → base58Decode → strip multicodec prefix [0xed, 0x01]
             → [32]byte public key (constant-time prefix check)

Adding a new algorithm

  1. Write it in Rust first (drs-core/src/)
  2. Add or extend shared conformance vectors when the protocol surface changes
  3. Port it to Go if the verifier needs the same rule on the hot path
  4. Keep TypeScript logic aligned with the conformance contract

Security-sensitive code checklist

Before merging any change to the crypto or verification path:

  • Comparisons on key material use constant-time equality (subtle::ConstantTimeEq / crypto/subtle.ConstantTimeCompare)
  • No unwrap() in Rust library code — use Result<T, E> and propagate
  • No _ on error returns in Go production paths — check and propagate
  • Signing keys are not logged, even in debug
  • New error messages do not expose key material or sensitive internal state