Skip to content
Proposed specification for review. We are seeking feedback on key architectural choices in the industry consultation.

Cross-Language Interoperability

PDTF 2.0 provides four language implementations that are proven to be interoperable through shared deterministic test vectors.

A credential signed in any language can be verified in any other language. This isn’t aspirational — it’s tested on every commit.

OperationTypeScriptRustPythonC#
Key generation✅✅✅✅
did:key derivation✅✅✅✅
VC signing (eddsa-jcs-2022)✅✅✅✅
VC verification✅✅✅✅
Status list create/check✅✅✅✅
TIR path matching✅✅✅✅
DID document resolution✅✅✅✅

The TypeScript reference implementation generates test-vectors/vectors.json from a fixed Ed25519 seed. Every other language consumes these vectors and validates its output matches exactly.

@pdtf/core (TypeScript)
│
├── generates test-vectors/vectors.json
│ │
│ ├── pdtf-core (Rust) consumes → 6 integration tests
│ ├── pdtf-core (Python) consumes → 10 pytest tests
│ └── Pdtf.Core (C#) consumes → 9 xUnit tests
│
└── self-validates → 17 vitest tests
{
"keys": {
"seed": "ababab...",
"publicKeyHex": "248acb...",
"did": "did:key:z6Mk...",
"publicKeyMultibase": "z6Mk..."
},
"signing": [
{
"name": "minimal-vc",
"unsignedVc": { ... },
"signedVc": { ... },
"proofValue": "z3vv14hX..."
}
],
"verification": [
{ "name": "valid-signature", "expectedValid": true },
{ "name": "tampered-subject", "expectedValid": false },
{ "name": "wrong-key", "expectedValid": false }
],
"statusList": { ... },
"tirPathMatching": [ ... ]
}
Test CategoryWhat’s ComparedPass Criteria
Key derivationdid:key string from raw public keyExact string match
SigningProof value from same unsigned VC + key + timestampByte-identical Ed25519 signatures
VerificationValid/tampered/wrong-key outcomesBoolean match
Status listsDecoded bit arrays from encoded bitstringsLogical equivalence (decoded bytes identical)
TIR matchingPattern + path → match resultBoolean match

Note on gzip: Different gzip implementations may produce different compressed byte sequences for the same data. Status list tests compare decoded content (logical equivalence), not raw base64 strings. This is by design — the W3C Bitstring Status List spec defines the logical format, not the compression output.


LanguageFrameworkTestsStatus
TypeScriptVitest68 (17 vector)✅ Passing
Rustcargo test84 (6 cross-lang)✅ Passing
Pythonpytest10✅ Passing
C#xUnit9 cross-lang + 5 unit✅ Written (needs .NET SDK)

Total: 172+ tests across 4 languages.


To add PDTF support in a new language:

  1. Implement the core operations: key generation, JCS canonicalization, SHA-256, Ed25519 signing, base58-btc encoding
  2. Download test-vectors/vectors.json from the core-rs repository
  3. Write tests that consume the vectors — every test category must pass
  4. Submit a PR to add your language to the interop matrix

The vector file is the contract. If your implementation produces the same outputs for the same inputs, it’s compatible.


Terminal window
cd core-ts
npx tsx scripts/generate-vectors.ts
# Copies to test-vectors/vectors.json
# Then copy to Rust repo
cp test-vectors/vectors.json ../core-rs/test-vectors/

⚠️ Do not change the seed or timestamps — all existing tests depend on deterministic output.