A live cross-implementation test against the canonical W3C VC-DI EdDSA
test vectors (https://github.com/w3c/vc-di-eddsa/tree/main/TestVectors/eddsa-rdfc-2022)
exposes three concrete divergences between our v0.1
oracle/signing/vc_di.py implementation and the W3C VC Data Integrity 2.0
specification + the published eddsa-rdfc-2022 cryptosuite spec.
The W3C reference vector does NOT verify through
verify_data_integrity_proof as currently implemented. The live test
is at
tests/integration/sign/test_live_vc_di.py
and is currently @pytest.mark.xfail(strict=True) pending resolution.
Divergence 1: proofValue encoding (multibase vs base64)
- W3C VC-DI 2.0 mandates multibase-base58btc with the
z prefix
(sec:proofValue is datatyped as sec:multibase).
- Our
sign_and_attach emits base64; our verify_data_integrity_proof
consumes base64.
Cross-impl impact: a W3C-compliant proofValue is unreadable by us,
and ours is unreadable by any conformant W3C verifier (Digital Bazaar,
Spruce, etc.).
Divergence 2: proof block as JSON-LD 1.1 @graph container
The W3C credentials/v2 context (https://www.w3.org/ns/credentials/v2)
defines the proof property as a JSON-LD 1.1 graph container. When the
reference vector is parsed by rdflib:
- The credential's
sec:proof predicate's object is a BNode that
serves as the graph identifier (e.g.,
Na3f59b4a4a72467d94972308a543c01f).
- The proof body's properties (
cryptosuite, verificationMethod,
proofValue, …) are attached to a different BNode (e.g.,
Nd616528988ed41d2a047261e6a4a41b5) representing the proof object
itself.
Our verifier looks up the proof body's properties by graph.triples((proof_iri, None, None))
where proof_iri is whatever sec:proof points at — which is the
graph BNode, not the proof body BNode. Result:
VerificationError: unknown or missing cryptosuite: None.
The fix is more than a syntax tweak — we need to either:
- accept both shapes (flat triple-block and graph-container) at
read time, or
- materialize from JSON-LD via
Dataset and walk the named graphs.
Divergence 3: signing payload composition
W3C eddsa-rdfc-2022 §3.2.2 defines the signature payload as
SHA-256(canonicalize(document-without-proof)) ‖ SHA-256(canonicalize(proof-config))
where proof-config is the proof block minus the proofValue.
Our _serialize_payload returns the raw N-Quads of
canonicalize(graph_without_proofs) and signs that directly.
This is the deepest of the three — it means even with #1 and #2 fixed,
the signatures still won't match.
Cross-impl impact: same as #1 — bidirectional incompatibility with
any W3C-conformant implementation.
Decision needed
- Option A — make v0.1 W3C-conformant. Rewrite
sign_and_attach
and verify_data_integrity_proof to: emit/accept multibase-base58btc
proofValue with sec:multibase datatype; handle the @graph
container case at parse; sign/verify against the hash-concat payload.
Pros: actual interop with the ecosystem; aligns with parsimony
("compose battle-tested standards"). Cons: bigger change than v0.1
budget anticipated.
- Option B — document the divergence and ship a
flexo-rtm-eddsa-rdfc-2022
private cryptosuite identifier, with W3C conformance deferred to
v0.2. The current cryptosuite identifier (eddsa-rdfc-2022) misleads
adopters into expecting interop; rename to a private suite ID and
call it out in Signed Envelope Shapes.
- Option C — hybrid: ship the W3C-conformant code path under a new
cryptosuite name in v0.1, keep the v0.1 implementation usable as-is
for internal use, deprecate the latter.
Adopters who actually need to consume W3C VC-DI signatures from
Digital Bazaar / Spruce / etc. would land on Option A or C; pure
self-signing self-verifying flexo-rtm deployments are fine on B.
A live cross-implementation test against the canonical W3C VC-DI EdDSA
test vectors (https://github.com/w3c/vc-di-eddsa/tree/main/TestVectors/eddsa-rdfc-2022)
exposes three concrete divergences between our v0.1
oracle/signing/vc_di.pyimplementation and the W3C VC Data Integrity 2.0specification + the published eddsa-rdfc-2022 cryptosuite spec.
The W3C reference vector does NOT verify through
verify_data_integrity_proofas currently implemented. The live testis at
tests/integration/sign/test_live_vc_di.pyand is currently
@pytest.mark.xfail(strict=True)pending resolution.Divergence 1:
proofValueencoding (multibase vs base64)zprefix(
sec:proofValueis datatyped assec:multibase).sign_and_attachemits base64; ourverify_data_integrity_proofconsumes base64.
Cross-impl impact: a W3C-compliant
proofValueis unreadable by us,and ours is unreadable by any conformant W3C verifier (Digital Bazaar,
Spruce, etc.).
Divergence 2: proof block as JSON-LD 1.1
@graphcontainerThe W3C credentials/v2 context (https://www.w3.org/ns/credentials/v2)
defines the
proofproperty as a JSON-LD 1.1 graph container. When thereference vector is parsed by rdflib:
sec:proofpredicate's object is a BNode thatserves as the graph identifier (e.g.,
Na3f59b4a4a72467d94972308a543c01f).cryptosuite,verificationMethod,proofValue, …) are attached to a different BNode (e.g.,Nd616528988ed41d2a047261e6a4a41b5) representing the proof objectitself.
Our verifier looks up the proof body's properties by
graph.triples((proof_iri, None, None))where
proof_iriis whateversec:proofpoints at — which is thegraph BNode, not the proof body BNode. Result:
VerificationError: unknown or missing cryptosuite: None.The fix is more than a syntax tweak — we need to either:
read time, or
Datasetand walk the named graphs.Divergence 3: signing payload composition
W3C eddsa-rdfc-2022 §3.2.2 defines the signature payload as
SHA-256(canonicalize(document-without-proof)) ‖ SHA-256(canonicalize(proof-config))where
proof-configis the proof block minus theproofValue.Our
_serialize_payloadreturns the raw N-Quads ofcanonicalize(graph_without_proofs)and signs that directly.This is the deepest of the three — it means even with #1 and #2 fixed,
the signatures still won't match.
Cross-impl impact: same as #1 — bidirectional incompatibility with
any W3C-conformant implementation.
Decision needed
sign_and_attachand
verify_data_integrity_proofto: emit/accept multibase-base58btcproofValue with
sec:multibasedatatype; handle the@graphcontainer case at parse; sign/verify against the hash-concat payload.
Pros: actual interop with the ecosystem; aligns with parsimony
("compose battle-tested standards"). Cons: bigger change than v0.1
budget anticipated.
flexo-rtm-eddsa-rdfc-2022private cryptosuite identifier, with W3C conformance deferred to
v0.2. The current cryptosuite identifier (
eddsa-rdfc-2022) misleadsadopters into expecting interop; rename to a private suite ID and
call it out in
Signed Envelope Shapes.cryptosuite name in v0.1, keep the v0.1 implementation usable as-is
for internal use, deprecate the latter.
Adopters who actually need to consume W3C VC-DI signatures from
Digital Bazaar / Spruce / etc. would land on Option A or C; pure
self-signing self-verifying flexo-rtm deployments are fine on B.