feat: DataProofsDotnet.Legacy — Ed25519Signature2020 / EcdsaSecp256r1Signature2019 (#7)#8
Conversation
Ship the pre–Data-Integrity Linked-Data-Signature cryptosuites as a new opt-in `DataProofsDotnet.Legacy` package: `Ed25519Signature2020` and `EcdsaSecp256r1Signature2019`, each with a JCS variant (default) and an RDFC-1.0 variant, implementing `ICryptosuite`. They create and verify through `DataIntegrityProofPipeline` — create dispatches by `cryptosuite` naming the suite, verify dispatches by proof `type` via `GetByProofType` — emitting `type:"<suite>"`, no `cryptosuite`, and a base58-btc `proofValue`. The wire convention and signing bytes are byte-identical to zcap-dotnet, locked by a cross-stack golden vector. No changes to `DataProofsDotnet.Core`; the suites are not in `CreateDefault()`. Adversarial-review fixes: - JCS fails closed on a document already carrying a `proof` member (cannot bind a W3C proof chain); RDFC binds chains natively. - JCS strips null object members before canonicalizing (zcap byte-identity). - Documented limitations: RDFC binds only @context-defined terms (inherent to JSON-LD/RDFC); EcdsaSecp256r1Signature2019 does not enforce low-s (malleable proofValue, not a unique id). Full solution: 778 tests pass, 0 warnings. Closes #7 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
moisesja
left a comment
There was a problem hiding this comment.
PR Review — DataProofsDotnet.Legacy (Ed25519Signature2020 / EcdsaSecp256r1Signature2019)
The implementation is well-structured. The base-class split (LegacyCryptosuiteBase → concrete suites), the fail-closed JCS chain guard, null-member stripping for byte identity with zcap, and the documented limitations (RDFC term-binding, ECDSA malleability) are all solid. The adversarial-review summary in the description is exactly the right level of transparency.
CI — 4 failures, breakdown
| Job | Root cause | Introduced by this PR? |
|---|---|---|
build + test (windows-latest) |
66 RdfCanonicalizationConformanceTests fail: expected length 87 vs actual 86 at index 85 — CRLF vs LF line ending in test fixtures on Windows |
No — pre-existing RDFC issue |
ac-5 didcomm JWS/JWE behavior parity |
Parity tool: commit e98570cd… not found in .parity-src/didcomm-dotnet |
No — pre-existing fetch/SHA issue |
ac-10 pack, install, and smoke |
Smoke script hardcodes version="0.1.0" but packages ship as 0.1.0-preview.2 |
No — pre-existing version mismatch |
ac-9 samples coverage gate |
Two uncovered public members | Yes — needs to be fixed before merge |
Blocking: ac-9 — missing sample coverage for two new public APIs
The gate reports:
UNCOVERED: DataProofsDotnet.DataIntegrity.CryptosuiteRegistry.GetByProofType
UNCOVERED: DataProofsDotnet.DataIntegrity.ICryptosuite.SupportedProofTypes
Both members were introduced (or promoted to required public surface) by this PR to enable legacy proof-type dispatch. A DataProofsDotnet.Samples.DataIntegrityLegacy sample project should be added that demonstrates:
- Registering
Ed25519Signature2020Cryptosuite/EcdsaSecp256r1Signature2019Cryptosuiteexplicitly (not viaCreateDefault). - A create→verify round-trip that exercises the
type-based dispatch path (GetByProofType), so the coverage scanner sees the member referenced. SupportedProofTypessurfaced — either called directly or observed via the dispatch path.
This is exactly what AC-9/FR-21 checks: every public member visible to the surface scan must appear in at least one sample.
Non-blocking observations
LegacyCryptosuiteBaseisinternal abstract— good; consumers only touch the two concrete public types.- Verify fallback order (JCS → RDFC): A short comment noting that a failed JCS verify incurs a second RDFC canonicalization pass on the same document would help future readers reason about performance on hot verification paths.
RdfcDocumentCanonicalizeralways allocated even for JCS-only usage (LegacyCryptosuiteBase.cs:457). The existing comment explains the rationale (immutability/thread-safety). Valid trade-off — just worth noting if allocation cost becomes a concern for high-throughput callers.
Fix the ac-9 gate (add a Legacy sample covering the two uncovered members) and this is ready to merge. The three pre-existing CI failures are out of scope for this change.
Generated by Claude Code
PR #8 review: the `ac-9` samples-coverage gate failed — `CryptosuiteRegistry .GetByProofType` and `ICryptosuite.SupportedProofTypes` (the legacy dispatch hooks) were referenced by no sample. - Add `DataProofsDotnet.Samples.DataIntegrityLegacy`: registers the legacy suites explicitly, create→verify round-trips both suites (JCS) plus the RDFC variant, exercises `GetByProofType` and `SupportedProofTypes`, asserts type-only wire shape (no cryptosuite), and a tamper negative. Exit 0 on success. - Close the root-cause gap: the coverage gate only scanned the original five package assemblies, so the new `DataProofsDotnet.Legacy` public surface escaped AC-9. Add it to the gate (assemblies array + project reference) and the five→six wording. Gate now: 528 members across 6 packages, 0 uncovered. - Wire the sample into the solution and samples/README. - Non-blocking review note: document the JCS→RDFC verify fallback's second canonicalization pass in LegacyCryptosuiteBase. Full solution: 778 tests pass, build 0/0, sample exits 0, coverage gate green. The three pre-existing CI failures (windows CRLF/LF, ac-5 parity SHA, ac-10 smoke version) are out of scope per the review. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed the blocking
Local: build 0/0, full solution 778 tests pass, sample exits 0, coverage gate green. The three pre-existing CI failures (windows CRLF/LF in RDFC fixtures, |
Summary
Closes #7. Ships the pre–Data-Integrity Linked-Data-Signature cryptosuites as a new opt-in
DataProofsDotnet.Legacypackage, building on the #4 verify-dispatch hook (0.1.0-preview.2).Ed25519Signature2020Cryptosuite(Ed25519) andEcdsaSecp256r1Signature2019Cryptosuite(P-256), each implementingICryptosuite.JCS(document with the proof nested under "proof", minus proofValue/cryptosuite), fed directly to the signer (the 2020-era convention — not the 2022 separate-config + hash-concat).SHA-256(RDFC(proofOptions)) ‖ SHA-256(RDFC(document)).DataIntegrityProofPipeline: create dispatches bycryptosuite(the suite'sName); verify dispatches by prooftypeviaGetByProofType. Emitted proof carriestype:"<suite>", nocryptosuite, base58-btcproofValue.DataProofsDotnet.Corechanges; the suites are not inCryptosuiteRegistry.CreateDefault()— register them explicitly.Byte-identity with zcap-dotnet (interop-critical)
The wire convention and signing bytes were reproduced from zcap's reference (
ProofSigningPayloadBuilder+CryptoSuite) and are locked by a cross-stack golden vector: a zcap-issuedEd25519Signature2020proof verifies through the pipeline, and re-signing the same input with the same seed reproduces zcap's exactproofValue.Adversarial review — findings fixed
A multi-agent review (spec → implement → tests → adversarial verify) surfaced and these were resolved:
previousProofchain. Now fails closed when the unsecured document already carries aproofmember (create throws; verify does not pass). RDFC binds chains natively. →LegacyChainBindingTestsStripNullMembers. →JcsNullMemberByteIdentityTests@context-defined terms (members it does not define are dropped by RDF expansion — inherent to JSON-LD/RDFC, shared with the conformantrdfc-*suites). Documented on the suite/enum/CHANGELOG/PRD and pinned by characterization tests contrasting JCS (binds verbatim) vs RDFC. →RdfcExtensionBindingCharacterizationTestssnot enforced (matches zcap + modern suites; enforcing it would break byte-compat).proofValues are malleable and must not be used as unique identifiers.Acceptance criteria
DataProofsDotnet.Legacy(not inCreateDefault).DataIntegrityProofPipeline;type:"<suite>", nocryptosuite, base58-btcproofValue.capabilityChain) participate in the JCS signed bytes and round-trip; tamper fails closed.Verification
dotnet build DataProofsDotnet.sln→ 0 warnings, 0 errors (warnings-as-errors).dotnet test DataProofsDotnet.sln→ 778 passed, 0 failed (Legacy 39; no regressions in Core/Rdfc/Jose/Cose). AC-6 dependency-hygiene gate green (dotNetRDF reaches Legacy only transitively via theRdfcproject reference).🤖 Generated with Claude Code