This crate is a DIDComm V2 vade plugin that currently offers:
type
It implements the following [VadePlugin
] functions:
didcomm_send
]didcomm_receive
]Currently supported protocols:
trust_ping
]did_exchange
]present_proof
]issue_credential
]presentation_exchange
]didcomm_send
prepares a message for being sent to the recipient and didcomm_receive
is used for decryption and analyzing an incoming message. Per default each sent message will be encrypted, either with the saved encryption key from an existing DID exchange with the communication partner, or with the provided one. Specific protocol types can override the encryption setting of a message to just send a plain message (like DID exchange).
NOTE: When you send any message that will be encrypted, you need to have a finished DID exchange or correct encryption keys, that are passed to vade_didcomm.
The two functions [didcomm_send
] and [didcomm_receive
] can be called with two parameters, options
and message
:
json
{
"encryptionKeys": {
"encryptionMySecret": "...",
"encryptionOthersPublic": "..."
},
"signingKeys": {
"signingMySecret": "...",
"signingOthersPublic": "..."
}
}
The result of both functions will always return a stringified json with almost same structure, only difference is that didcomm_receive
doesn't return messageRaw
property, the return has following pattern:
json
{
"message": {},
"messageRaw": {},
"metadata": {}
}
json
{
"message": {},
"metadata": {}
}
The data that is represented in message
and metadata
is protocol specific. The message is also attached unencrypted as messageRaw
.
This protocol implementation has only 2 steps and is used more like a testing protocol.
To send a trust_ping
message, pass the following message to the didcomm_send
:
json
{
"type": "https://didcomm.org/trust_ping/1.0/ping",
"from": "did::xyz:34r3cu403hnth03r49g01",
"to": [ "did::xyz:34r3cu403hnth03r49g03" ],
}
This will return an encrypted stringified message and will also add a body to the message, that contains:
json
{
"body": {
"response_requested": true
}
}
The [DID exchange protocol
] is a bit more complex and consist of 3 steps. The whole flow is implemented in the [did-exchange test
]. Like with the trustping, you can pass a simple message, that will be enhanced with the actual data that will be sent. Here an example for the first request (ensure, to set the serviceendpoint to the url, where your DID agent is available):
json
{
"type": "https://didcomm.org/didexchange/1.0/request",
"service_endpoint": "https://evan.network",
"from": "did:uknow:d34db33d",
"to": ["did:uknow:d34db33f"]
}
This will return the following result:
json
{
"message": {
"body": {
"@context": "https://w3id.org/did/v1",
"authentication": [
"{0}#key-1"
],
"id": "did:uknow:d34db33d",
"publicKey": [
{
"id": "did:uknow:d34db33d#key-1",
"publicKeyBase58": "b1f88eebc9576fcb923837d9455ffd24a2c634d95e4e7c9fdf0ab362fd092a7c",
"type": [
"Ed25519VerificationKey2018"
]
}
],
"service": [
{
"id": "did:uknow:d34db33d#didcomm",
"priority": 0,
"recipientKeys": [
"b1f88eebc9576fcb923837d9455ffd24a2c634d95e4e7c9fdf0ab362fd092a7c"
],
"serviceEndpoint": "",
"type": "did-communication"
}
]
},
"from": "did:uknow:d34db33d",
"id": "de9358ae810341e6b02bc08f7fd061ec",
"pthid": "de9358ae810341e6b02bc08f7fd061ec#key-1",
"thid": "did:uknow:d34db33d#key-1",
"to": [
"did:uknow:d34db33f"
],
"type": "https://didcomm.org/didexchange/1.0/request"
},
"metadata": {
"pub_key": "b1f88eebc9576fcb923837d9455ffd24a2c634d95e4e7c9fdf0ab362fd092a7c",
"secret_key": "487db1e4be6f0ec0cb4fa07a64a5aea9bd5e77ba8f639e8595563535c5784166",
"target_pub_key": "",
"target_service_endpoint": ""
}
}
As you can see, the whole message was enriched with the data that is necessary for the DID exchange. The metadata contains the generated communication hex encoded public key and secret key. The receiver can just pass the whole json to the didcomm_receive
function, that will analyse the message, will save the communication keys and generate new ones for himself as well. The receiver can then use the logic for sending the response, by just replacing the type of the message https://didcomm.org/didexchange/1.0/response.
The [Present Proof Protocol
] consists of 4 steps. The whole flow is implemented in the [present-proof test
]. The general flow starts with a verifier sending a request-presentation
message to a prover. The prover has the option to answer with the requested presentation or propose a new presentation to the verifier. The format for request-presentation
is the following:
json
{
"@type": "https://didcomm.org/present-proof/1.0/request-presentation",
"@id": "<uuid-request>",
"comment": "some comment",
"request_presentations~attach": [
{
"@id": "libindy-request-presentation-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
The prover then responds with either a presentation
or propose-presentation
message. The following are the formats for the messages:
Presentation response format:
json
{
"@type": "https://didcomm.org/present-proof/1.0/presentation",
"@id": "<uuid-presentation>",
"comment": "some comment",
"presentations~attach": [
{
"@id": "libindy-presentation-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
Presentation proposal format:
json
{
"@type": "https://didcomm.org/present-proof/1.0/presentation-preview",
"attributes": [
{
"name": "<attribute_name>",
"cred_def_id": "<cred_def_id>",
"mime-type": "<type>",
"value": "<value>",
"referent": "<referent>"
},
// more attributes
],
"predicates": [
{
"name": "<attribute_name>",
"cred_def_id": "<cred_def_id>",
"predicate": "<predicate>",
"threshold": "<threshold>"
},
// more predicates
]
}
Once the presentation exchange is complete, the verifier sends an ack message to the prover to confirm the receival and validity of the received Presentation data.
The [Issue Credential Protocol
] consists of 5 steps. The whole flow is implemented in the [issue-credential test
]. The general flow starts with a holder sending a propose-credential
message to a issuer. The issuer has the option to answer with the offer-credential
or terminate request with problem-report
message. Holder receives offer-credential
and decides to send request-credential
message , Once issuer receives request-credential
, he/she would respond with issue-credential
and Holder will receive and send ack
message to acknowledge the receipt of credential.
Propose Credential message:
json
{
"@type": "https://didcomm.org/issue-credential/1.1/propose-credential",
"@id": "<uuid-of-propose-message>",
"comment": "some comment",
"credential_proposal": "<json-ld object>",
"schema_issuer_did": "DID of the proposed schema issuer",
"schema_id": "Schema ID string",
"schema_name": "Schema name string",
"schema_version": "Schema version string",
"cred_def_id": "Credential Definition ID string",
"issuer_did": "DID of the proposed issuer"
}
Offer Credential message :
json
{
"@type": "https://didcomm.org/issue-credential/1.0/offer-credential",
"@id": "<uuid-of-offer-message>",
"comment": "some comment",
"credential_preview": "<json-ld object>",
"offers~attach": [
{
"@id": "libindy-cred-offer-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
Request Credential message:
json
{
"@type": "https://didcomm.org/issue-credential/1.0/request-credential",
"@id": "<uuid-of-request-message>",
"comment": "some comment",
"requests~attach": [
{
"@id": "attachment id",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
},
]
}
Issue Credential message:
json
{
"@type": "https://didcomm.org/issue-credential/1.0/issue-credential",
"@id": "<uuid-of-issue-message>",
"comment": "some comment",
"credentials~attach": [
{
"@id": "libindy-cred-0",
"mime-type": "application/json",
"data": {
"base64": "<bytes for base64>"
}
}
]
}
The [Presentation Exchange Protocol
] consists of 3 steps. The whole flow is implemented in the [presentation-exchange test
]. The general flow starts with a verifier sending a request-presentation
message to a holder. The holder has an option to answer with the propose-presentation
or send presentation
message. Once Verifier receives presentation
message, he/she will match the received credential claims against presentation-definition
request and validate the claims values with the contraints present in the input-descriptors
array in presentation-definition
In the current implementation of presentation exchange protocol, the json schema constraints have to be verified by the client application which is using vade because the constraints are quite diverse and specific to application requirements, for details regarding constraints, please visit [Presentation Exchange Protocol
].
request-presentation message:
json
{
"options": {
"challenge": "...",
"domain": "...",
},
"presentation_definition": {
// presentation definition object
}
}
presentation-definition example:
json
{
"comment": "Note: VP, OIDC, DIDComm, or CHAPI outer wrapper would be here.",
"presentation_definition": {
"id": "32f54163-7166-48f1-93d8-ff217bdb0653",
"input_descriptors": [
{
"id": "wa_driver_license",
"name": "Washington State Business License",
"purpose": "We can only allow licensed Washington State business representatives into the WA Business Conference",
"schema": [{
"uri": "https://licenses.example.com/business-license.json"
}]
}
]
}
}
presentation message example:
json
{
"@type": "https://didcomm.org/present-proof/%VER/presentation",
"@id": "f1ca8245-ab2d-4d9c-8d7d-94bf310314ef",
"comment": "some comment",
"formats" : [{
"attach_id" : "2a3f1c4c-623c-44e6-b159-179048c51260",
"format" : "dif/presentation-exchange/submission@v1.0"
}],
"presentations~attach": [{
"@id": "2a3f1c4c-623c-44e6-b159-179048c51260",
"mime-type": "application/ld+json",
"data": {
"json": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://identity.foundation/presentation-exchange/submission/v1"
],
"type": [
"VerifiablePresentation",
"PresentationSubmission"
],
"presentation_submission": {
"descriptor_map": [{
"id": "citizenship_input",
"path": "$.verifiableCredential.[0]"
}]
},
"verifiableCredential": [{
"@context": "https://www.w3.org/2018/credentials/v1",
"id": "https://eu.com/claims/DriversLicense",
"type": ["EUDriversLicense"],
"issuer": "did:foo:123",
"issuanceDate": "2010-01-01T19:73:24Z",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"license": {
"number": "34DGE352",
"dob": "07/13/80"
}
},
"proof": {
"type": "RsaSignature2018",
"created": "2017-06-18T21:19:10Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "https://example.edu/issuers/keys/1",
"jws": "..."
}
}],
"proof": {
"type": "RsaSignature2018",
"created": "2018-09-14T21:19:10Z",
"proofPurpose": "authentication",
"verificationMethod": "did:example:ebfeb1f712ebc6f1c276e12ec21#keys-1",
"challenge": "1f44d55f-f161-4938-a659-f8026467f126",
"domain": "4jt78h47fh47",
"jws": "..."
}
}
}
}]
}
Each protocol is represented by a set of steps. To register a new protocol, just follow the following steps:
src/protocols
This file can look like following:
```rs
pub struct CustomBody {
custom: Option
pub fn generatemycustomprotocol() -> Protocol { let mut protocol = Protocol { name: String::from("mycustom_protocol"), steps: Vec::new(), };
protocol.steps.push(send_step("step1", send_step1));
protocol.steps.push(receive_step("step1", receive_step1));
return protocol;
}
pub fn sendstep1(options: &str, message: &str) -> StepResult {
let mut parsedmessage: MessageWithBody
pub fn receivestep1(options: &str, message: &str) -> StepResult { return generatestepoutput(message, "{}"); } ```
mod.rs
filers
pub(crate) mod my_custom_protocol;
protocol_handler.rs
rs
let protocols: [&Protocol; 3] = [
&generate_did_exchange_protocol(),
&generate_ping_pong_protocol(),
&my_custom_protocol(),
];
Afterwards, you can just test your protocol by passing the following message to the DIDComm functions:
json
{
"type": "my_custom_protocol/step1",
"from": "did::xyz:34r3cu403hnth03r49g01",
"to": [ "did::xyz:34r3cu403hnth03r49g03" ],
}