DidComm.Adapters.NetDid 1.4.1

Prefix Reserved
dotnet add package DidComm.Adapters.NetDid --version 1.4.1
                    
NuGet\Install-Package DidComm.Adapters.NetDid -Version 1.4.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DidComm.Adapters.NetDid" Version="1.4.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DidComm.Adapters.NetDid" Version="1.4.1" />
                    
Directory.Packages.props
<PackageReference Include="DidComm.Adapters.NetDid" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DidComm.Adapters.NetDid --version 1.4.1
                    
#r "nuget: DidComm.Adapters.NetDid, 1.4.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DidComm.Adapters.NetDid@1.4.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DidComm.Adapters.NetDid&version=1.4.1
                    
Install as a Cake Addin
#tool nuget:?package=DidComm.Adapters.NetDid&version=1.4.1
                    
Install as a Cake Tool

didcomm-dotnet

NuGet License .NET Status Spec

A .NET 10 implementation of DIDComm Messaging v2.1 — the DIF protocol for confidential, integrity-protected, optionally non-repudiable messaging between parties identified by Decentralized Identifiers (DIDs).

DIDComm gives two parties a way to exchange messages whose trust derives from control of DIDs rather than from CAs, IdPs, or transport-level TLS. It is message-based, asynchronous, simplex, and transport-agnostic.

DID resolution is delegated to the sibling library NetDid — didcomm-dotnet implements only the messaging layer (message model, JOSE envelopes, routing, threading, OOB, and the protocols defined directly in the spec).

Quickstart

Two identities, an authcrypt round-trip, and the metadata the envelope actually proved — no network, no key management setup.

dotnet add package DidComm.Core
dotnet add package DidComm.Extensions.DependencyInjection
// An in-memory secrets resolver stands in for your KMS/HSM. Nothing here touches a network:
// did:peer:2 encodes its own DID document, so resolution is a local parse.
var secrets = new InMemorySecretsResolver();
var services = new ServiceCollection();
services.AddDidComm(b => b.UseNetDidResolver().UseSecretsResolver(secrets));
await using var sp = services.BuildServiceProvider();

var alice = await PeerIdentityFactory.CreateAsync(
    sp.GetRequiredService<IDidManager>(), sp.GetRequiredService<IKeyGenerator>(), sp.GetRequiredService<ICryptoProvider>());
var bob = await PeerIdentityFactory.CreateAsync(
    sp.GetRequiredService<IDidManager>(), sp.GetRequiredService<IKeyGenerator>(), sp.GetRequiredService<ICryptoProvider>());
foreach (var key in alice.Privates.Concat(bob.Privates))
    secrets.Add(key);

var client = sp.GetRequiredService<DidCommClient>();
var message = new MessageBuilder()
    .WithType("https://example.com/protocols/hello/1.0/greeting")
    .WithFrom(alice.Did)
    .WithTo(bob.Did)
    .WithBody(new JsonObject { ["text"] = "Hello, Bob." })
    .Build();

var packed = await client.PackEncryptedAsync(message, new PackEncryptedOptions([bob.Did], From: alice.Did));
var received = await client.UnpackAsync(packed.Message);

Console.WriteLine($"body          : {received.Message.Body}");
Console.WriteLine($"authenticated : {received.Authenticated}");   // the sender proved control of Alice's key
Console.WriteLine($"encrypted     : {received.Encrypted}");
Console.WriteLine($"sender kid    : {received.SenderKid}");
Console.WriteLine($"addressed to  : {received.RecipientAddressing}");
body          : {
  "text": "Hello, Bob."
}
authenticated : True
encrypted     : True
sender kid    : did:peer:2.Ez6LSi8yoKGbLoTZBB9FMrmpvtaaGcsNHEv4Cj6xAXwAdYbe7.Vz6MkemzLKfrkRqb1NRU5EA4xwGqz1xaCG2KHNAqArWtYeQUV#key-1
addressed to  : Addressed

authenticated is the line that matters: it is evidence from ECDH-1PU that the sender controls Alice's key, not a claim the message makes about itself. addressed to is the advisory FR-CONSIST-04 check — act on NotAddressed, but never treat Addressed as authorization, since to is written by the sender.

The 24 lines above are the body of samples/01-Quickstart's RunAsync, minus its closing return — a compiled project whose smoke test runs on every build, so the snippet cannot drift from code that works. Copy Program.cs instead of the block above if you want the using directives with it. The two DIDs are generated per run, so only the sender kid line differs from what you see here. InMemorySecretsResolver and PeerIdentityFactory are sample/test helpers, deliberately kept out of DidComm.Core (DD-02); in a real agent those are your KMS and your own identity provisioning.

Project status

Phases 0–6 complete. The library has a public Pack / Unpack / Send surface (DidCommClient), DID resolution via NetDid 3.1.0, a consumer-supplied ISecretsResolver contract, the three protective envelope shapes (signed / anoncrypt / authcrypt) and their legal compositions, addressing consistency including same-document key provenance, DID rotation via from_prior, Routing Protocol 2.0 (sender forward wrapping + mediator relay + rewrapping), and the HTTPS / WebSocket transports plus the ASP.NET Core receive endpoints. Phase 6 has landed threading / ACKs / i18n / profiles and all the spec's built-in protocols — Trust Ping, Discover Features, Empty, Report Problem, Trace (off by default), and Out-of-Band 2.0 — plus the NuGet release pipeline. The DIDComm v2.1 Appendix C inbound interop gate passes for every vendored vector.

Phase 6 also landed the live cross-implementation interop harness, the full sample set with an execution-based public-API coverage gate, and the observability and benchmark NFRs — see Roadmap for the per-item status and tools/interop-live/README.md for what each interop run actually executes.

Shipped highlights:

  • Public facadeservices.AddDidComm(b => …)Pack{Plaintext,Signed,Encrypted}Async + UnpackAsync + SendAsync. Auto-detects envelope shape on unpack, enforces FR-API-05 (expires_time) and FR-API-06 (MaxReceiveBytes), surfaces FR-API-04 metadata on every unpack.
  • DID resolution via the NetDidKeyService adapter over net-did. UseNetDidResolver() wires did:key and did:peer; its configure callback takes any other net-did method you add. JWK + Multikey verification methods are both supported, and did:web is deliberately refused at every entry point with UnsupportedDidMethodException (DD-08).
  • Same-document key provenance — a sender/signer is never authorized against a different DID-document version than the one that supplied the key the JOSE layer verified with, and the exact evidence (kid / DID / controller / relationship / thumbprint) is surfaced on UnpackResult as VerifiedKeyBinding.
  • DID rotationMessage.FromPrior carries a JWT validated against the prior DID's authentication relationship; FR-ROT-03 enforced (rotation messages MUST be encrypted).
  • Routing & mediationPackEncryptedAsync(... Forward: true) resolves the recipient's DIDCommMessaging service (object / array-of-objects / opt-in DD-10 bare-string), implicitly prepends mediator keyAgreement keys (FR-ROUTE-04), reverse-order anoncrypt-wraps a forward per routing key, and surfaces the transport URI on PackEncryptedResult.ServiceEndpoint. ForwardProcessor handles the mediator side with optional rewrapping (FR-ROUTE-05/06).
  • TransportsDidCommClient.SendAsync(...) packs and dispatches via an ITransportRouter. DidComm.Transports.Http ships a Polly-backed HTTPS sender (FR-TRN-04..08); DidComm.Transports.WebSocket ships a one-message- per-envelope WS sender with connection pool + exponential reconnect (FR-TRN-09..11). DidComm.AspNetCore provides MapDidCommEndpoint / MapDidCommWebSocket / MapDidCommOobEndpoint minimal-API extensions — Content-Type validation ⇒ 415, MaxReceiveBytes ⇒ 413 / 1009 (FR-TRN-07 + FR-API-06).
  • Built-in protocols — every protocol the spec defines directly: Trust Ping 2.0, Discover Features 2.0, Empty 1.0, Report Problem 2.0 (taxonomy + interpolation + escalation + cascade guard), Trace 2.0 (off by default), and Out-of-Band 2.0 (OutOfBand.CreateInvitation / ToUrl / FromUrl, short-form ?_oobid= retrieval, web_redirect).
  • Inbound observationIProtocolObserver lets an application watch inbound traffic whose PIURI a built-in handler owns, without replacing that handler. Delivered off the dispatch path through a bounded queue, from an immutable verified snapshot, so an observer can neither gate replies nor be handed content the unpack never verified.

The unit and interop suites build and run under /warnaserror on Linux and Windows on every PR (ci.yml). See CHANGELOG.md for the per-release log, the PRD for normative requirements (the six-phase plan is §12), and the roadmap below for status at a glance.

Install

didcomm-dotnet ships as focused NuGet packages (hybrid packaging, DD-03) — the core plus one package per transport and integration. The badge at the top of this file shows the current version.

Package What it gives you
DidComm.Core Message model, JWE/JWS envelopes, pack/unpack, routing, rotation, threading, and the built-in protocols (Trust Ping, Discover Features, Empty, Report Problem, Trace, Out-of-Band)
DidComm.Extensions.DependencyInjection AddDidComm(...) wiring with net-did resolution
DidComm.AspNetCore MapDidCommEndpoint / MapDidCommWebSocket / MapDidCommOobEndpoint receive endpoints
DidComm.Transports.Http, DidComm.Transports.WebSocket Sender-side transport bindings
DidComm.Adapters.NetDid Optional bridge from a NetDid key store to ISecretsResolver
dotnet add package DidComm.Core
dotnet add package DidComm.Extensions.DependencyInjection

Releases are tag-driven: pushing a vMAJOR.MINOR.PATCH tag runs .github/workflows/release.yml, which packs every package (with symbols + SourceLink) and pushes to NuGet.org behind a reviewer-approved environment gate. Maintainers: see RELEASING.md for the runbook.

What "spec-complete" means

didcomm-dotnet implements the messaging layer of DIDComm Messaging v2.1:

Area Scope
Envelopes Plaintext, Signed (JWS), Anoncrypt (JWE/ECDH-ES+A256KW), Authcrypt (JWE/ECDH-1PU+A256KW), and all legal compositions
Signing algorithms EdDSA (Ed25519), ES256 (P-256), ES256K (secp256k1)
Key-agreement curves X25519, P-256, P-384 (required); P-521 (optional)
Content encryption A256CBC-HS512 (required), A256GCM (recommended), XC20P (optional)
DID resolution Delegated to NetDid. Wired by default: did:key, did:peer. Any other net-did method (e.g. did:webvh) plugs into UseNetDidResolver(b => …)
Routing & mediation Forward protocol, mediator relay, rewrapping mode
Transports HTTPS (send + ASP.NET Core receive), WebSocket
Protocols Trust Ping 2.0, Discover Features 2.0, Report Problem 2.0, Out-of-Band 2.0, Empty 1.0, Trace 2.0
Cross-message Threading, ACK loop-guards, DID rotation (from_prior), i18n/accept-lang, profile negotiation

did:web is explicitly NOT supported. This is a deliberate security policy (DD-08), not a messaging-conformance gap. See PRD §1.1 and §15.

The conformance gate is the spec's own Appendix C test vectors — which pass today — plus a live cross-implementation harness (FR-IX-03/04/05/06/08). The harness round-trips against SICPA's didcomm-python and didcomm-jvm in both directions and feeds our published vectors to each for external verification (tools/interop-live); didcomm-rust participates as harvested static vectors only, not a live leg. Fixtures come tagged by sourcespec-v2.1 for the Appendix C set, plus vectors harvested from the reference implementations and the didcomm-dotnet set this repo publishes.

Package map

Package Responsibility
DidComm.Core Message model; JWE/JWS envelopes; pack/unpack/send facade; IDidKeyService / IDidKeyBindingService + NetDidKeyService resolver adapter; ISecretsResolver contract; from_prior rotation; Routing Protocol 2.0 (forward wrapping + mediator processing + service-endpoint resolution); the built-in protocols and the dispatcher/observer seam; transport abstractions (IDidCommTransport, ITransportRouter); typed exception hierarchy
DidComm.Extensions.DependencyInjection IServiceCollection.AddDidComm(b => b.UseNetDidResolver().UseSecretsResolver<T>().UseHttpTransport().UseWebSocketTransport().AddBuiltInProtocols().Configure(...)); FR-SEC-02 fail-fast on missing registrations
DidComm.Adapters.NetDid Optional bridge from NetDid.Core.IKeyStoreISecretsResolver (FR-SEC-04, SHOULD); documented scope (sign-side surface only — see class XML doc)
DidComm.Transports.Http HTTPS sender (FR-TRN-04..08): IHttpClientFactory-backed POST, manual 307 follow + 301/308 refusal, Polly retry / circuit-breaker / timeout
DidComm.Transports.WebSocket WebSocket sender (FR-TRN-09..11): one binary message per packed envelope, per-endpoint pool, Polly exponential reconnect, lifecycle events
DidComm.AspNetCore Minimal-API extensions: MapDidCommEndpoint (HTTP receive, FR-TRN-07), MapDidCommWebSocket (WS receive with frame reassembly, FR-TRN-09/10), MapDidCommOobEndpoint (short-form OOB retrieval); MaxReceiveBytes ⇒ 413 / 1009 (FR-API-06)
DidComm.TestSupport (not shipped) InMemorySecretsResolver for tests and samples — deliberately kept out of DidComm.Core per DD-02

The spec's built-in protocols live inside DidComm.Core, not in separate DidComm.Protocols.* packages: they are part of what makes an agent conformant, so splitting them out would only let a consumer assemble a non-conformant install.

Naming convention

The repository is didcomm-dotnet (kebab-case, matching net-did and zcap-dotnet). .NET assemblies, NuGet packages, and namespaces use the PascalCase root DidComm (e.g. DidComm.Core, DidComm.Transports.Http). The acronym "DIDComm" from the spec is rendered DidComm in code per .NET capitalization guidelines for 3+ letter acronyms (matching NetDid). Prose references to the protocol keep the spec spelling "DIDComm".

Public API at a glance

// The facade — DidComm.Facade.DidCommClient
public sealed class DidCommClient
{
    public Task<string>              PackPlaintextAsync(Message m,                              CancellationToken ct = default);
    public Task<string>              PackSignedAsync(Message m, string signFrom,                CancellationToken ct = default);
    public Task<PackEncryptedResult> PackEncryptedAsync(Message m, PackEncryptedOptions opts,   CancellationToken ct = default);
    public Task<SendResult>          SendAsync(Message m, SendOptions opts,                     CancellationToken ct = default);
    public Task<UnpackResult>        UnpackAsync(string packed,                                 CancellationToken ct = default);
}

// What an unpack proved (FR-API-04) — DidComm.Facade.UnpackResult (selected members)
public sealed record UnpackResult
{
    public bool                Encrypted { get; }           // confidentiality
    public bool                Authenticated { get; }       // authcrypt proved the sender's key
    public bool                NonRepudiation { get; }      // a signature a third party can check
    public VerifiedKeyBinding? SenderKeyBinding { get; }    // the exact key + document that verified
    public RecipientAddressing RecipientAddressing { get; } // FR-CONSIST-04 advisory: are we in 'to'?
}

// DID resolution adapter — DidComm.Resolution
public interface IDidKeyService
{
    Task<IReadOnlyList<Jwk>> GetVerificationMethodsAsync(string did, VerificationRelationship rel, CancellationToken ct = default);
    Task<bool>               IsKeyAuthorizedAsync(string did, string kid, VerificationRelationship rel, CancellationToken ct = default);
    void                     RejectUnsupportedMethod(string did);  // throws UnsupportedDidMethodException for did:web
}

// Since 1.4.0 the unpack path takes its evidence from this capability instead. A key service that
// also implements it is used for sender/signer/recipient provenance, and IsKeyAuthorizedAsync is
// then no longer called during unpack — exactly one resolution per key, and every field of the
// returned binding comes from that one document. Decorators MUST forward the interface or they
// silently fall back to the legacy path.
public interface IDidKeyBindingService
{
    Task<ResolvedKeyBinding?> ResolveKeyBindingAsync(string kid, VerificationRelationship relationship, CancellationToken ct = default);
}

// Consumer-supplied secrets (KMS / HSM / Vault) — DidComm.Secrets
public interface ISecretsResolver
{
    Task<Jwk?>                  FindAsync(string kid,                       CancellationToken ct = default);
    Task<IReadOnlyList<string>> FindPresentAsync(IEnumerable<string> kids,  CancellationToken ct = default);
}

// Read-only inbound observation — DidComm.Protocols
public interface IProtocolObserver
{
    string? ProtocolUriFilter { get; }                       // null observes everything
    Task    OnMessageReceivedAsync(InboundObservation observation, CancellationToken ct);
}

// Transport binding — DidComm.Transports
public interface IDidCommTransport
{
    string                Scheme { get; }
    bool                  CanHandle(Uri endpoint);
    Task<TransportResult> SendAsync(TransportRequest request, CancellationToken ct);
}

// DI wiring — DidComm.Extensions.DependencyInjection
services.AddDidComm(b =>
{
    b.UseNetDidResolver();                     // did:key + did:peer via net-did
    b.UseSecretsResolver<MyVaultResolver>();   // FR-SEC-02 fail-fast if absent
    b.UseHttpTransport();                      // FR-TRN-04..08 (Polly resilience)
    b.UseWebSocketTransport();                 // FR-TRN-09..11
    b.AddBuiltInProtocols();                   // Trust Ping, Discover Features, Empty, Report Problem
    b.Configure(o =>
    {
        o.MaxReceiveBytes = 1 * 1024 * 1024;
        o.OwnIdentifiers = ["did:peer:2…"];    // makes the FR-CONSIST-04 warning reachable
    });
});
var client = sp.GetRequiredService<DidCommClient>();

// Server side — DidComm.AspNetCore
app.MapDidCommEndpoint("/didcomm",      async (unpacked, ct) => { /* host dispatch */ });
app.MapDidCommWebSocket("/ws/didcomm",  async (unpacked, ct) => { /* host dispatch */ });

Samples

Sample What it shows
samples/01-Quickstart The quickstart above: two identities, authcrypt round-trip, unpack metadata
samples/02-Cookbook One narrated section per API task (all 28 PRD §14.2 letters) — run dotnet run --project samples/02-Cookbook
samples/03-EnvelopesAndMessages Every envelope composition and content-encryption alg, multi-recipient, attachments, threading + ACKs, DID rotation
samples/04-MediatorAgent ASP.NET Core mediator + Routing 2.0 relay; Alice→Mediator→Bob over HTTP with DID-published routingKeys
samples/05-WebSocketChat Two agents over WebSocket: trust-ping, discover-features, chat, reconnect after drop
samples/06-OutOfBand OOB invitation → URL/QR → decode → pthid-correlated response
samples/07-ProblemsAndProtocols Problem-report taxonomy, escalation, cascade guard, empty-ACK, custom lets_do_lunch handler
samples/08-Extensibility Custom (mock-KMS) secrets resolver, the net-did IKeyStore bridge, custom transport
samples/09-NetDidIntegration did:key / did:peer minting, Ed25519→X25519 derivation, the deliberate did:web rejection
samples/10-ProfilesAndI18n accept profile negotiation and lang/accept-lang (the spec's chess example)

Every sample builds and runs in CI via an in-process smoke test, and the FR-DX-01 coverage gate (tests/DidComm.InteropTests/DxCoverage/) fails the build if a public member of the shipped packages is not demonstrated. The gate measures execution, not mention: it instruments the six shipped assemblies and re-runs all ten samples plus the 28 cookbook sections in-process, then intersects real execution hits with the public surface. Currently 572 of 585 members are proven to execute; the remaining 13 have no executable code at all (enums, const holders, one static readonly field) and are itemized in the test output. The execution gate's allowlist is empty; a cheaper metadata-reference gate runs alongside it as a first check and carries 12 justified entries for members no sample references directly.

Specifications

Specification Version Reference
DIDComm Messaging v2.1 (Editor's Draft, WG Approved) identity.foundation/didcomm-messaging/spec/v2.1
JSON Web Encryption (JWE) RFC 7516 rfc7516
JSON Web Signature (JWS) RFC 7515 rfc7515
JSON Web Algorithms (JWA) RFC 7518 rfc7518
ECDH-1PU draft-madden-jose-ecdh-1pu-04 draft-madden-jose-ecdh-1pu
W3C DIDs v1.0 w3.org/TR/did-core

Roadmap

didcomm-dotnet is delivered in six phases (see PRD §12 for the full plan, exit criteria, and per-phase agent kickoff prompts):

Phase Scope Status
0 Repository & JOSE-composition substrate (ICryptoProvider, AEAD, AES-KW, 1PU KDF wrapper, JWK shim, fixtures harness) ✅ Complete
1 Message model, attachments, MTURI parsing, consistency-check functions ✅ Complete
2 Envelopes: Signed, Anoncrypt, Authcrypt — Appendix C interop gate ✅ Complete
3 Pack/Unpack facade, NetDid integration, secrets, DID rotation ✅ Complete
4 Routing & mediation (Forward protocol, mediator-as-DID-endpoint, rewrapping) ✅ Complete
5 Transports (HTTPS + ASP.NET Core receive, WebSocket) ✅ Complete
6 Protocols, cross-message concerns, live interop, samples, release ✅ Complete

Phase 6, in detail:

Item Status
Built-in protocols, OOB 2.0, threading/ACKs, profiles & i18n ✅ Done
NuGet release pipeline (tag-driven, gated) ✅ Done
Fixture submodule + harvested vectors + published didcomm-dotnet vectors (FR-IX-03/06) ✅ Done — didcomm-dotnet-fixtures
Live interop harness — both directions vs didcomm-python and didcomm-jvm over did:peer, nightly job (FR-IX-04/05/08) ✅ Done — tools/interop-live
Sample applications 03–10 and cookbook tasks A–J/L/Y/Z (FR-DX-04, §14.3) ✅ Done
Public-API coverage gate + §14.4 matrix (FR-DX-01, FR-DX-09) ✅ Done — 572/585 members proven to execute; 13 have no executable code
ActivitySource spans with redaction audit (NFR-04/05) and the BenchmarkDotNet suite (NFR-07) ✅ Done

The conformance bar is binary: MUST requirements implemented, full Appendix C vector suite passes, the cross-implementation interop matrix passes — inbound static vectors harvested from SICPA Python, JVM and Rust, plus live round-trips against didcomm-python and didcomm-jvm (didcomm-rust is static-vector only; there is no live Rust leg) — every public API member exercised by a runnable sample, and the README quickstart works unmodified. Cells a counterpart genuinely cannot run are declared n/a with a falsifiable cause and are listed in tools/interop-live/README.md; an n/a that stops being true is deleted, not renewed.

Repository layout

didcomm-dotnet/
├── src/
│   ├── DidComm.Core/                              # message model, envelopes, facade, resolution, secrets, rotation, routing, protocols, transport abstractions
│   ├── DidComm.Extensions.DependencyInjection/    # services.AddDidComm(b => …)
│   ├── DidComm.Adapters.NetDid/                   # optional NetDid.IKeyStore → ISecretsResolver bridge
│   ├── DidComm.Transports.Http/                   # Polly-backed HTTPS sender (FR-TRN-04..08)
│   ├── DidComm.Transports.WebSocket/              # WebSocket sender with pool + reconnect (FR-TRN-09..11)
│   └── DidComm.AspNetCore/                        # MapDidCommEndpoint / MapDidCommWebSocket / MapDidCommOobEndpoint
├── tests/
│   ├── DidComm.Core.Tests/                        # unit tests
│   ├── DidComm.InteropTests/                      # Appendix C vectors + Appendix B resolution + facade round-trip + rotation + routing + transports + sample smoke tests
│   └── DidComm.TestSupport/                       # InMemorySecretsResolver helper (non-test library)
├── samples/
│   ├── _shared/                                   # Narrator + PeerIdentityFactory (did:peer:2 via NetDid)
│   ├── 01-Quickstart/                             # the README quickstart, compiled and CI-verified
│   ├── 02-Cookbook/                               # one narrated section per PRD §14.2 API task (A–BB)
│   └── 03…10                                      # the §14.3 sample applications (see the Samples table)
├── tools/
│   ├── FixtureGen/                                # emits the published `source: didcomm-dotnet` vectors (FR-IX-06)
│   ├── InteropCli/                                # mint/pack/unpack CLI for the live harness
│   └── interop-live/                              # cross-impl harness vs didcomm-python / didcomm-jvm (FR-IX-04/05)
├── benchmarks/
│   └── DidComm.Benchmarks/                        # NFR-07 BenchmarkDotNet suite (results in its README)
├── docs/
│   └── didcomm-dotnet_PRD.md                      # normative product requirements
├── tasks/                                         # phased todo files + lessons.md
├── Directory.Build.props
├── Directory.Packages.props
└── DidComm.sln

Interop fixtures (Appendix A/B/C, harvested didcomm-rust/-python/-jvm vectors, our own published set) live in the standalone didcomm-dotnet-fixtures repository, wired in as a git submodule at tests/DidComm.InteropTests/fixtures (PRD §13.3). Clone with --recurse-submodules, or run git submodule update --init after a plain clone.

Contributing

didcomm-dotnet welcomes contributions. The PRD is the source of truth for what to build; contributors should read it before opening non-trivial PRs. See CONTRIBUTING.md for setup, code conventions, and the phased delivery model.

If you're filing an issue or PR for a specific requirement, please reference its ID (e.g. FR-ENC-13) — the PRD is structured so that traceability stays tight.

Security

didcomm-dotnet handles cryptographic key material and implements security-critical primitives (JWE, JWS, ECDH-1PU, AES-CBC-HMAC). If you discover a vulnerability, do not open a public issue. See SECURITY.md for the responsible-disclosure process.

Code of Conduct

This project follows the Contributor Covenant. By participating, you agree to uphold its terms.

  • NetDid — W3C DID Core 1.0 implementation; provides DID resolution to didcomm-dotnet
  • zcap-dotnet — Authorization Capabilities (ZCAP-LD) for .NET

License

Licensed under the Apache License 2.0. See also NOTICE.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.4.1 37 8/7/2026
1.4.0 213 7/31/2026
1.3.0 189 7/20/2026
1.2.0 229 7/14/2026
1.1.0 198 6/22/2026
1.0.0 122 6/17/2026
0.1.0-preview.1 59 6/2/2026