feat(sdk): implement did:key v0.7 resolution across Go, Python, TS SDKs#958
Merged
Conversation
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.
Contributor
There was a problem hiding this comment.
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:keyv0.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
didand resolved DID Document match pinned fixtures byte-for-byte (structural JSON equality where appropriate). - Re-enable the
did:key resolutionrow in the conformance page and updatescripts/conformance_matrixmetadata + 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. |
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.
7 tasks
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.
This was referenced Jul 17, 2026
ojongerius
added a commit
that referenced
this pull request
Jul 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements
did:keyv0.7 generation and resolution (ADR-0007) in all three SDKs and wiresspec/test-vectors/did-key/vectors.jsoninto a real cross-SDK conformance suite.didpackage/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:keyidentifier → resolved DID Document (singleMultikeyverification method, per the ADR's wire shape)sdk/go/did/vectors_test.go,sdk/py/tests/test_did_key_vectors.py,sdk/ts/src/did-key-vectors.test.ts) asserting the computeddidanddid_documentmatch the 3 frozen fixtures byte-for-byte0,O,I,l), wrong decoded length, wrong multicodecdid:key resolutionrow from all-dash to real ✓/✓/✓, updatescount.py'sconsumersfield and its honesty-guard test (test_did_key_marked_wired_into_all_three_sdks), adds run-it-yourself commandsobsigna/__init__.py,sdk/ts/src/index.ts; Go packages are imported directly)Why
Closes #956. The
did:keytest 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 (replacingdid:agent:/did:user:placeholders, the daemon'sdid:user:unknowndefault, and the verification algorithm update) as future, separately-scoped work.Checklist
go vet,ruff check,biome)-tags=integrationsuites re-verified unaffected)spec/files touched; only SDK code,scripts/, andsite/docsSecurity
did:keyresolution is a pure string transform (no signing/verification), but marking for visibility since it's identity-adjacentResolve/resolve/resolveDidreject wrong prefix, invalid base58btc characters, wrong decoded length, and wrong multicodec explicitly