Skip to content

feat(sdk): implement did:key v0.7 resolution across Go, Python, TS SDKs#958

Merged
ojongerius merged 4 commits into
mainfrom
worktree-issue-956-did-key
Jul 3, 2026
Merged

feat(sdk): implement did:key v0.7 resolution across Go, Python, TS SDKs#958
ojongerius merged 4 commits into
mainfrom
worktree-issue-956-did-key

Conversation

@ojongerius

Copy link
Copy Markdown
Contributor

What

Implements did:key v0.7 generation and resolution (ADR-0007) in all three SDKs and wires spec/test-vectors/did-key/vectors.json into a real cross-SDK conformance suite.

  • New did package/module per SDK — sdk/go/did, sdk/py/src/obsigna/did.py, sdk/ts/src/did.ts — each exposing:
    • FromPublicKey / from_public_key / didFromPublicKey: raw 32-byte Ed25519 public key → did:key:z<base58btc(0xed01 || pubkey)>
    • Resolve / resolve / resolveDid: did:key identifier → resolved DID Document (single Multikey verification method, per the ADR's wire shape)
    • A hand-rolled base58btc encoder/decoder in each language — no new dependency, given the project's supply-chain-conscious dependency policy for a small, easily-verified algorithm
  • Vector runner in each SDK (sdk/go/did/vectors_test.go, sdk/py/tests/test_did_key_vectors.py, sdk/ts/src/did-key-vectors.test.ts) asserting the computed did and did_document match the 3 frozen fixtures byte-for-byte
  • Unit tests per SDK covering the ADR's MUST-reject cases: wrong prefix, excluded base58btc characters (0, O, I, l), wrong decoded length, wrong multicodec
  • Conformance page: flips the did:key resolution row from all-dash to real ✓/✓/✓, updates count.py's consumers field and its honesty-guard test (test_did_key_marked_wired_into_all_three_sdks), adds run-it-yourself commands
  • Both new functions are re-exported from each SDK's top-level package (obsigna/__init__.py, sdk/ts/src/index.ts; Go packages are imported directly)

Why

Closes #956. The did:key test vectors existed as spec-side reference fixtures only — no SDK implemented resolution, so the Conformance page carried an honest but conspicuous all-dash row. This lands the minimal Phase A slice ADR-0007 scoped (SDK generation/resolution + conformance wiring), leaving the broader Phase A items (replacing did:agent:/did:user: placeholders, the daemon's did:user:unknown default, and the verification algorithm update) as future, separately-scoped work.

Checklist

  • Tests pass for all changed components (Go, Python, TypeScript — unit + vector-runner + full existing suites)
  • Linter passes (go vet, ruff check, biome)
  • No real keys or secrets in the diff (only RFC 8032 §7.1 test vectors / W3C registry public keys)
  • Cross-language tests pass (existing -tags=integration suites re-verified unaffected)
  • AGENTS.md updated — not needed, no project-structure change
  • Spec changes reviewed by a maintainer — no spec/ files touched; only SDK code, scripts/, and site/ docs

Security

  • This PR touches crypto, auth, or secrets handling — did:key resolution is a pure string transform (no signing/verification), but marking for visibility since it's identity-adjacent
  • Primitives and parameters have been reviewed — base58btc + multicodec framing match ADR-0007 exactly, cross-checked against 3 independent SDK implementations
  • All inputs are validated at trust boundaries — Resolve/resolve/resolveDid reject wrong prefix, invalid base58btc characters, wrong decoded length, and wrong multicodec explicitly
  • Edge cases are tested (nil, empty, corrupted, concurrent) — empty string, missing prefix, excluded base58 chars, truncated/oversized payload, wrong multicodec, zero-length/oversized public keys

Wires spec/test-vectors/did-key/vectors.json into a real cross-SDK
conformance suite (ADR-0007). Each SDK gets a standalone did package
(base58btc encode/decode, FromPublicKey/did_from_public_key/
didFromPublicKey, Resolve/resolve/resolveDid) with no new dependencies,
plus a vector runner asserting the computed did and did_document match
the frozen fixtures byte-for-byte.

Flips the did:key resolution row on the Conformance page from all-dash
to real Go/Py/TS checkmarks, updates count.py's consumers field and its
honesty-guard test, and adds explicit run-it-yourself commands.

Closes #956
Resolve/resolve/resolveDid ran the base58btc decode's O(n^2)
big-integer multiply-accumulate loop on the full input before checking
the decoded payload length, letting a few-hundred-KB did:key string
tie up a core for tens of seconds in any of the three SDKs. Add a
64-character bound (a 34-byte payload never needs more than 47) on the
encoded portion, checked before decoding.

Also, from code review:
- Export base58btcEncode (TS) so did.test.ts reuses the real encoder
  for malformed-payload fixtures instead of hand-duplicating it.
- Stop did_test.go's TestBase58EncodeDecodeRoundTrip from overwriting
  its own leading-zero-byte test cases before encoding them, which
  left the zeros-handling path untested.
- Replace the hand-rolled hex decoders in the new TS test files with
  the SDK's existing Buffer.from(hex, "hex") idiom.
Merges origin/main, which landed the on_page mechanism and CI
reconciliation test (cross-sdk-tests/conformance_page_test.go) that
issue #956's did:key row was meant to flip. Resolves conflicts by:

- count.py: flip did:key resolution's on_page back to True (default)
  now that all three SDKs consume it.
- test_count.py: replace test_did_key_is_off_page with
  test_did_key_is_on_page, asserting the flip.
- conformance.mdx: re-add the did:key resolution row to the matrix
  with real Go/Py/TS checkmarks; adopt main's count-agnostic honesty
  callout (44 canonicalization / 7 MUST-reject, matching the
  reconciliation test's regexes) and drop the now-resolved "no SDK
  implements did:key resolution yet" caveat.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements ADR-0007 did:key v0.7 generation + resolution across the Go, Python, and TypeScript SDKs, and wires the existing spec/test-vectors/did-key/vectors.json fixtures into executable cross-SDK conformance tests and the published conformance matrix.

Changes:

  • Add did:key v0.7 generation (FromPublicKey / from_public_key / didFromPublicKey) and resolution (Resolve / resolve / resolveDid) implementations in Go/Python/TypeScript, including a dependency-free base58btc codec.
  • Add per-SDK unit tests and vector runners that assert the did and resolved DID Document match pinned fixtures byte-for-byte (structural JSON equality where appropriate).
  • Re-enable the did:key resolution row in the conformance page and update scripts/conformance_matrix metadata + honesty-guard tests to reflect that it’s now wired in.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
site/src/content/docs/conformance.mdx Adds did:key resolution to the published matrix and documents how to run the per-SDK vector checks.
sdk/ts/src/index.ts Re-exports did:key APIs and types from the TS SDK entrypoint.
sdk/ts/src/did.ts Implements did:key v0.7 generation/resolution and base58btc in TypeScript.
sdk/ts/src/did.test.ts Adds TS unit tests for didFromPublicKey/resolveDid reject/accept behavior and DoS bound.
sdk/ts/src/did-key-vectors.test.ts Adds TS runner for spec/test-vectors/did-key/vectors.json.
sdk/py/src/obsigna/did.py Implements did:key v0.7 generation/resolution and base58btc in Python.
sdk/py/src/obsigna/init.py Re-exports Python did:key APIs and types from the top-level package.
sdk/py/tests/test_did.py Adds Python unit tests for from_public_key/resolve, including reject cases and encode/decode round-trip.
sdk/py/tests/test_did_key_vectors.py Adds Python runner for spec/test-vectors/did-key/vectors.json.
sdk/go/did/did.go Implements did:key v0.7 generation/resolution and document shape in Go.
sdk/go/did/base58.go Adds dependency-free base58btc encode/decode implementation in Go.
sdk/go/did/did_test.go Adds Go unit tests for generation/resolution reject/accept behavior and DoS bound.
sdk/go/did/vectors_test.go Adds Go integration-tagged runner for spec/test-vectors/did-key/vectors.json.
scripts/conformance_matrix/count.py Updates did:key resolution metadata (consumers) and effectively flips it on-page via default on_page=True.
scripts/conformance_matrix/test_count.py Updates honesty-guard tests to enforce that did:key resolution is on-page and consumed by Go/Py/TS.

Comment thread scripts/conformance_matrix/count.py
Per Copilot review on #958: VectorSet.on_page's field comment and
scripts/conformance_matrix/AGENTS.md both named did:key resolution as
the current example of an off-page reference-fixture set. That's no
longer true now that did:key is wired into all three SDKs and
on_page=True — rewrite both to describe the mechanism generically
instead of naming a set that may or may not currently use it.
@ojongerius
ojongerius merged commit b5ce936 into main Jul 3, 2026
37 checks passed
@ojongerius
ojongerius deleted the worktree-issue-956-did-key branch July 3, 2026 01:51
ojongerius added a commit that referenced this pull request Jul 17, 2026
Cuts the Unreleased CHANGELOG section (response disclosure #819, did:key
v0.7 #958, checkpoint package extraction #932, protocol version 0.6.0,
x/crypto security bump) into a released version. Unblocks #978: no
published sdk/go version currently contains the checkpoint package, so
daemon's GOWORK=off release build fails on that import.
ojongerius added a commit that referenced this pull request Jul 17, 2026
Cuts the Unreleased CHANGELOG section (did:key v0.7 resolution, #958)
into a released version. Catches sdk-ts up with the sdk-go release
(#979) -- this feature landed across all three SDKs simultaneously but
only Go has shipped it so far.
ojongerius added a commit that referenced this pull request Jul 17, 2026
Cuts the Unreleased CHANGELOG section into a released version:
target_system/target_resource on DaemonEmitter.emit() (#946) and
did:key v0.7 resolution (#958). Both landed cross-SDK; TS and Go have
now caught up (#942/#979, #983) -- this closes the gap for Python.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wire did:key resolution vectors into a cross-SDK conformance suite

2 participants