affinidi_tdk_vdsp 1.0.0
affinidi_tdk_vdsp: ^1.0.0 copied to clipboard
A Dart package for implementing the Verifiable Data Sharing Protocol (VDSP) using DIDComm v2.1 to facilitate secure data sharing.
Affinidi VDSP for Dart #
A Dart package for implementing the Verifiable Data Sharing Protocol (VDSP), a protocol that facilitates secure, interoperable verifiable credential exchange between Holders and Verifiers using the DIDComm v2.1 protocol, an open standard for decentralised communication.
The VDSP package consist of two main classes:
-
VdspVerifierthat represents the requesting party (Verifier) that verifies one or more credentials, such as identity documents, educational certificates, or professional qualifications, as part of a workflow like background screening for employees. -
VdspHolderthat represents the user or entity (Holder) that possesses the credentials required by the verifiers. They have complete control over their data and how they are shared.
These classes simplify the data sharing over the DIDComm v2.1 protocol, including credential queries and cryptographic operations such as signature verifications.
VDSP classes provide developers with tools to build robust, privacy-first, and secure credential-sharing features into their applications. VDSP enables use cases such as:
- Customer onboarding and KYC (Know Your Customer)
- Background screening, including education credential verification
- Healthcare data sharing
These are a few scenarios from a wide range of use cases unlocked by VDSP that require selective disclosure of verified information while maintaining users' privacy and control over their data.
Table of Contents #
- Core Concepts
- Key Features
- Requirements
- Installation
- VDSP classes
- Usage
- Complete Example
- Security Features
- Support & Feedback
- Contributing
Core Concepts #
The Verifiable Data Sharing Protocol (VDSP) uses existing open standards, such as DIDComm v2.1, and cryptographic techniques to provide a secure, private, and verifiable data sharing flow.
-
DIDComm v2.1 protocol - An open standard for decentralised communication. Built on the foundation of Decentralised Identifiers (DIDs), it enables parties to exchange verifiable data such as credentials and establishes secure communication channels between parties without relying on centralised servers.
-
Verifiable Data Sharing Protocol (VDSP) - A protocol built on top of DIDComm v2.1 that enables secure sharing of verifiable credentials between holders and verifiers. VDSP defines message types, workflows, and security requirements for credential sharing. There are two main roles in the data-sharing flow:
-
Verifier - An entity that requests verifiable credentials from holders. The verifier can query holders for specific data using credential query language and verify the authenticity of the shared credentials.
-
Holder - An entity that stores and controls verifiable credentials. The holder can receive data requests, filter their credentials, and share selected credentials with verifiers through a verifiable presentation format.
-
-
DCQL (Digital Credential Query Language) - A standardised query language for requesting verifiable credentials. It allows verifiers to specify what credentials they need and what claims within those credentials are required.
-
Feature Discovery - A mechanism that allows verifiers and holders to discover each other's supported features, protocols, and operations before initiating data exchange. It ensures compatibility and prevents protocol mismatches.
-
Verifiable Presentation - A data structure containing one or more verifiable credentials, cryptographically signed by the holder to prove authenticity. It creates the presentation in response to a verifier's credential query.
Key Features #
- Implements the Verifiable Data Sharing Protocol (VDSP) for secure credential sharing.
- Implements DIDComm v2.1 protocol for secure, end-to-end encrypted communication.
- Support for feature discovery between verifiers and holders.
- Supports DCQL for credential querying and filtering.
- Cryptographically verifies the signature of verifiable presentations and credentials.
- Built-in support for proof context (challenge and domain) to prevent replay attack.
- Supports data integrity proof suites (ECDSA and EdDSA) for signing presentations.
- Problem reporting mechanism for error handling.
VDSP Protocol Support #
The package implements the following VDSP message types:
| Message Type | Purpose | Direction |
|---|---|---|
discover-features/2.0/queries |
Query Supported Features | Verifier → Holder |
discover-features/2.0/disclose |
Disclose Supported Features | Holder → Verifier |
vdsp/1.0/query-data |
Request Verifiable Credentials | Verifier → Holder |
vdsp/1.0/data-response |
Share Verifiable Presentation | Holder → Verifier |
vdsp/1.0/data-processing-result |
Send Processing Result | Verifier → Holder |
report-problem/2.0/problem-report |
Report Errors or Warnings | Any → Any |
Detailed protocol specification can be found here.
Supported Query Languages #
| Query Language | Status | Description |
|---|---|---|
| DCQL | ✅ Fully supported | Digital Credential Query Language for querying credentials from the holder's digital wallet |
Requirements #
- Dart SDK version ^3.6.0
Installation #
Run:
dart pub add affinidi_tdk_vdsp
or manually, add the package into your pubspec.yaml file:
dependencies:
affinidi_tdk_vdsp: ^<version_number>
and then run the command below to install the package:
dart pub get
VDSP Classes #
VdspVerifier #
The VdspVerifier implements the VDSP protocol for a verifier, enabling your application to:
- Discover supported features from holders using feature query.
- Request verifiable credentials from holders using DCQL queries.
- Automatically verifies verifiable presentations and credentials.
- Send processing results back to holders.
Key Methods:
queryHolderFeatures()- (verifier) sends a feature query to discover what the holder supports.queryHolderData()- (verifier) requests verifiable credentials from a holder using DCQL query.sendDataProcessingResult()- (verifier) sends a processing result message to the holder.listenForIncomingMessages()- (holder and verifier) Listens for incoming messages (disclose, data response, problem reports).
VdspHolder #
The VdspHolder implements the VDSP protocol for a holder, enabling your application to:
- Respond to feature queries with supported feature disclosures.
- Filter stored verifiable credentials based on DCQL queries from verifiers.
- Create and share verifiable presentations in response to data requests.
- Receive processing results from verifiers.
Key Methods:
getDisclosures()- Returns supported feature disclosures for a query message.disclose()- Sends a disclose message in response to a feature query.filterVerifiableCredentials()- Filters credentials using a DCQL query.shareData()- Creates and sends a verifiable presentation in response to a data request.listenForIncomingMessages()- Listens for incoming messages (feature queries, data requests, processing results, problem reports).
Usage #
Below is a step-by-step example of secure credential sharing between verifiers and holders using the VDSP protocol. The example demonstrates feature discovery, credential querying, and verification.
1. Set up DID Managers and Mediator #
Both the verifier and holder need DID managers and a connection to a DIDComm mediator:
// Resolve the mediator's DID document
final mediatorDid = 'did:web:...'; // Your mediator's DID
final mediatorDidDocument = await UniversalDIDResolver.defaultResolver.resolveDid(
mediatorDid,
);
// Set up verifier's DID manager
final verifierKeyStore = InMemoryKeyStore();
final verifierWallet = PersistentWallet(verifierKeyStore);
final verifierDidManager = DidKeyManager(
wallet: verifierWallet,
store: InMemoryDidStore(),
);
final verifierKeyId = 'verifier-key-1';
await verifierWallet.generateKey(
keyId: verifierKeyId,
keyType: KeyType.p256,
);
await verifierDidManager.addVerificationMethod(verifierKeyId);
// Set up holder's DID manager
final holderKeyStore = InMemoryKeyStore();
final holderWallet = PersistentWallet(holderKeyStore);
final holderDidManager = DidKeyManager(
wallet: holderWallet,
store: InMemoryDidStore(),
);
final holderKeyId = 'holder-key-1';
await holderWallet.generateKey(
keyId: holderKeyId,
keyType: KeyType.p256,
);
await holderDidManager.addVerificationMethod(holderKeyId);
2. Initialise VDSP Verifier #
Create a VDSP verifier for requesting credentials:
final vdspVerifier = await VdspVerifier.init(
mediatorDidDocument: mediatorDidDocument,
didManager: verifierDidManager,
);
3. Initialise VDSP Holder #
Create a VDSP holder for sharing credentials:
final vdspHolder = await VdspHolder.init(
mediatorDidDocument: mediatorDidDocument,
didManager: holderDidManager,
featureDisclosures: FeatureDiscoveryHelper.vdspHolderDisclosures,
);
4. Feature Discovery #
The verifier first queries the holder to discover supported features:
await vdspVerifier.queryHolderFeatures(
holderDid: (await holderDidManager.getDidDocument()).id,
featureQueries: FeatureDiscoveryHelper.getFeatureQueriesByDisclosures(
FeatureDiscoveryHelper.vdspHolderDisclosures,
),
);
// Verifier listens for disclose messages
vdspVerifier.listenForIncomingMessages(
onDiscloseMessage: (message) async {
print('Holder supports: \${message.body}');
// Check if holder supports required features
final body = DiscloseBody.fromJson(message.body!);
// Proceed with data query if features are supported
},
onDataResponse: (/* ... */) {
// Handle data response (see section 7)
},
);
// Holder listens for feature queries and responds
vdspHolder.listenForIncomingMessages(
onFeatureQuery: (message) async {
final disclosures = vdspHolder.getDisclosures(queryMessage: message);
await vdspHolder.disclose(
queryMessage: message,
disclosures: disclosures,
);
},
onDataRequest: (message) async {
// Handle data request (see section 6)
},
);
5. Query Holder Credentials #
After feature discovery, the verifier sends a DCQL query to request specific credentials:
import 'package:uuid/uuid.dart';
// Define what credentials the verifier needs
// In this example, verifier requests for holder's email address
final dcqlQuery = DcqlCredentialQuery(
credentials: [
DcqlCredential(
id: const Uuid().v4(),
format: CredentialFormat.ldpVc,
claims: [
DcqlClaim(
path: ['credentialSubject', 'email'],
),
],
),
],
);
// Send the query to the holder
await vdspHolder.queryHolderData(
holderDid: holderDid,
dcqlQuery: dcqlQuery,
operation: 'registerAgent', // Optional operation identifier
proofContext: VdspQueryDataProofContext(
challenge: 'unique-challenge-string',
domain: 'verifier.example.com',
),
comment: 'Please share your email credential',
);
6. Holder Shares Credentials #
The holder receives the query, filters existing credentials, and shares a verifiable presentation:
vdspHolder.listenForIncomingMessages(
onDataRequest: (message) async {
// Filter credentials based on the query
final queryResult = await vdspHolder.filterVerifiableCredentials(
requestMessage: message,
verifiableCredentials: holderVerifiableCredentials, // Holder's credentials
);
// Create a signer for the verifiable presentation
final holderSigner = await holderDidManager.getSigner(
holderDidManager.assertionMethod.first,
);
// Share the filtered credentials as a verifiable presentation
await vdspHolder.shareData(
requestMessage: message,
verifiableCredentials: queryResult.verifiableCredentials,
verifiablePresentationSigner: holderSigner,
verifiablePresentationProofSuite: DataIntegrityProofSuite.ecdsa_jcs_2019,
operation: 'registerAgent',
comment: 'Here is my email credential',
);
},
);
7. Process Data Response #
The verifier receives the verifiable presentation and automatically verifies it:
vdspVerifier.listenForIncomingMessages(
onDataResponse: ({
required VdspDataResponseMessage message,
required bool presentationAndCredentialsAreValid,
VerifiablePresentation? verifiablePresentation,
required VerificationResult presentationVerificationResult,
required List<VerificationResult> credentialVerificationResults,
}) async {
print('Verification result: \$presentationAndCredentialsAreValid');
if (presentationAndCredentialsAreValid) {
// Extract claims from the verified presentation
final email = verifiablePresentation
?.verifiableCredential
.first
.credentialSubject
.first['email'];
print('Verified email: \$email');
// Send processing result to holder
await vdspVerifier.sendDataProcessingResult(
holderDid: message.from!,
result: {
'success': true,
'email': email,
},
);
} else {
print('Verification failed:');
print('Presentation: \${presentationVerificationResult.errors}');
print('Credentials: \${credentialVerificationResults.map((r) => r.errors)}');
}
},
onProblemReport: (message) {
print('Problem reported: \${message.body}');
},
);
Complete Example #
See example/example.dart for a complete runnable example that demonstrates:
- Feature discovery between verifier and holder
- DCQL-based credential querying
- Verifiable presentation creation and sharing
- Automatic verification of presentations and credentials
- Processing result handling
Security Features #
-
Replay Attack Prevention: Utilises proof context through unique challenge and domain parameters, ensuring each credential presentation is bound to a specific request and cannot be reused maliciously.
-
Robust Data Integrity: Leverages the Data Integrity Proof Suite with support for both ECDSA and EdDSA algorithms to generate and verify digital signatures, guaranteeing the authenticity and tamper-evidence of credential data.
-
Automated Verification: Enables seamless and automated validation of verifiable presentations upon credential sharing by the holder, streamlining trust establishment between parties.
Support & Feedback #
If you face any issues or have suggestions, please don't hesitate to contact us using this link.
Reporting Technical Issues #
If you have a technical issue with the DIDComm's codebase, you can also create an issue directly in GitHub.
- Ensure the bug was not already reported by searching on GitHub under Issues.
- If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behaviour that is not occurring.
Contributing #
Want to contribute?
Head over to our CONTRIBUTING guidelines.