- Authors: Nikita Khateev
- Status: ACCEPTED
- Since: 2019-05-28
- Status Note: This v1.x version of the protocol will be replaced by version v2 defined in RFC 454.
- Supersedes: Indy HIPE PR #89; also Credential Exchange 0.1 -- IIW 2019
- Start Date: 2019-01-30
- Tags: feature, protocol, credentials, test-anomaly
Formalization and generalization of existing message formats used for presenting a proof according to existing RFCs about message formats.
We need to define a standard protocol for presenting a proof.
The present proof protocol consists of these messages:
- Propose Proof - Prover to Verifier (optional)
- Request Proof - Verifier to Prover
- Present Proof - Prover to Verifier
In addition, the ack
and problem-report
messages are adopted into the protocol for confirmation and error handling.
This protocol is about the messages to support the presentation of verifiable claims, not about the specifics of particular verifiable presentation mechanisms. This is challenging since at the time of writing this version of the protocol, there is only one supported verifiable presentation mechanism(Hyperledger Indy). DIDComm attachments are deliberately used in messages to try to make this protocol agnostic to the specific verifiable presentation mechanism payloads. Links are provided in the message data element descriptions to details of specific verifiable presentation implementation data structures.
Diagrams in this protocol were made in draw.io. To make changes:
- upload the drawing HTML from this folder to the draw.io site (Import From...GitHub),
- make changes,
- export the picture and HTML to your local copy of this repo, and
- submit a pull request.
- request-sent
- proposal-received
- request-received
- presentation-received
- done
- request-received
- proposal-sent
- presentation-sent
- reject-sent
- done
For the most part, these states map onto the transitions shown in the choreography diagram in obvious ways. However, a few subtleties are worth highlighting:
- The final transitions for the Verifier (Send Presentation Reject, Send Presentation Ack, and Receive Presentation Reject) all result in a final
done
state, but thisdone
may or may not be the Verifier's intended outcome. We may want to tweak this in a future version of the protocol. - A similar situation exists with the final transitions for the Prover and its final transitions (Send Presentation Reject, Receive Presentation Ack, and Receive Presentation Reject).
- When a Prover makes a (counter-)proposal, it transitions to the
proposal-sent
state. This state is only present by implication in the choreography diagram; it essentially equates to the null or begin state in that the Prover does nothing until a presentation request arrives, triggering the leftmost transition for the Prover.
Errors might occur in various places. For example, a Verifier might time out waiting for the Prover to supply a presentation. Errors trigger a problem-report
. In this version of the protocol, all errors cause the state of both parties (the sender and the receiver of the problem-report
) to revert to null
(meaning it is no longer engaged in the protocol at all). Future versions of the protocol may allow more granular choices.
An optional message sent by the Prover to the verifier to initiate a proof presentation process, or in response to a request-presentation
message when the Prover wants to propose using a different presentation format. Schema:
{
"@type": "https://didcomm.org/present-proof/1.0/propose-presentation",
"@id": "<uuid-propose-presentation>",
"comment": "some comment",
"presentation_proposal": <json-ld object>
}
Description of attributes:
comment
-- a field that provides some human readable information about the proposed presentation.presentation_proposal
-- a JSON-LD object that represents the presentation example that Prover wants to provide. It should follow the schema of Presentation Preview;
From a verifier to a prover, the request-presentation
message describes values that need to be revealed and predicates that need to be fulfilled. Schema:
{
"@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>"
}
}
]
}
Description of fields:
comment
-- a field that provides some human readable information about this request for a presentation.request_presentations~attach
-- an array of attachments defining the acceptable formats for the presentation.- For Indy, the attachment contains data from libindy about the presentation request, base64url-encoded, as returned from
libindy
. For more information see the Libindy API.
- For Indy, the attachment contains data from libindy about the presentation request, base64url-encoded, as returned from
This message is a response to a Presentation Request message and contains signed presentations. Schema:
{
"@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>"
}
}
]
}
Description of fields:
comment
-- a field that provides some human readable information about this presentation.presentations~attach
-- an array of attachments containing the presentation in the requested format(s).- For Indy, the attachment contains data from libindy that is the presentation, base64url-encoded, as returned from
libindy
. For more information see the Libindy API.
- For Indy, the attachment contains data from libindy that is the presentation, base64url-encoded, as returned from
Claims in Hyperledger Indy-based verifiable credentials are put into the credential in two forms, raw
and encoded
. raw
is the actual data value, and encoded
is the (possibly derived) integer value that is used in presentations. At this time, Indy does not take an opinion on the method used for encoding the raw value. This will change with the Rich Schema work that is underway in the Indy/Aries community, where the encoding method will be part of the credential metadata available from the public ledger.
Until the Rich Schema mechanism is deployed, the Aries issuers and verifiers must agree on an encoding method so that the verifier can check that the raw
value returned in a presentation corresponds to the proven encoded
value. The following is the encoding algorithm that MUST be used by Issuers when creating credentials and SHOULD be verified by Verifiers receiving presentations:
- keep any 32-bit integer as is
- for data of any other type:
- convert to string (use string "None" for null)
- encode via utf-8 to bytes
- apply SHA-256 to digest the bytes
- convert the resulting digest bytes, big-endian, to integer
- stringify the integer as a decimal.
An example implementation in Python can be found here.
A gist of test value pairs can be found here.
This is not a message but an inner object for other messages in this protocol. It is used to construct a preview of the data for the presentation. Its schema follows:
{
"@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
]
}
The preview identifies attributes and predicates to present.
The mandatory "attributes"
key maps to a list (possibly empty to propose a presentation with no attributes) of specifications, one per attribute. Each such specification proposes its attribute's characteristics for creation within a presentation.
The mandatory "name"
key maps to the name of the attribute.
The optional "cred_def_id"
key maps to the credential definition identifier of the credential with the current attribute. Note that since it is the holder who creates the preview and the holder possesses the corresponding credential, the holder must know its credential definition identifier.
If the key is absent, the preview specifies attribute's posture in the presentation as a self-attested attribute. A self-attested attribute does not come from a credential, and hence any attribute specification without the "cred_def_id"
key cannot use a "referent"
key as per Referent below.
The optional mime-type
advises the verifier how to render a binary attribute, to judge its content for applicability before accepting a presentation containing it. Its value parses case-insensitively in keeping with MIME type semantics of RFC 2045. If mime-type
is missing, its value is null.
The optional value
, when present, holds the value of the attribute to reveal in presentation:
- if
mime-type
is missing (null), thenvalue
is a string. In other words, implementations interpret it the same as any other key+value pair in JSON - if
mime-type
is not null, thenvalue
is always a base64url-encoded string that represents a binary BLOB, andmime-type
tells how to interpret the BLOB after base64-decoding.
An attribute specification must specify a value
, a cred_def_id
, or both:
- if
value
is present andcred_def_id
is absent, the preview proposes a self-attested attribute; - if
value
andcred_def_id
are both present, the preview proposes a verifiable claim to reveal in the presentation; - if
value
is absent andcred_def_id
is present, the preview proposes a verifiable claim not to reveal in the presentation.
The optional referent
can be useful in specifying multiple-credential presentations. Its value indicates which credential
will supply the attribute in the presentation. Sharing a referent
value between multiple attribute specifications indicates that the holder's same credential supplies the attribute.
Any attribute specification using a referent
must also have a cred_def_id
; any attribute specifications sharing a common referent
value must all have the same cred_def_id
value (see Credential Definition Identifier above).
For example, a holder with multiple account credentials could use a presentation preview such as
{
"@type": "https://didcomm.org/present-proof/1.0/presentation-preview",
"attributes": [
{
"name": "account",
"cred_def_id": "BzCbsNYhMrjHiqZDTUASHg:3:CL:1234:tag",
"value": "12345678",
"referent": "0"
},
{
"name": "streetAddress",
"cred_def_id": "BzCbsNYhMrjHiqZDTUASHg:3:CL:1234:tag",
"value": "123 Main Street",
"referent": "0"
},
],
"predicates": [
]
}
to prompt a verifier to request proof of account number and street address from the same account, rather than potentially an account number and street address from distinct accounts.
The mandatory "predicates"
key maps to a list (possibly empty to propose a presentation with no predicates) of predicate specifications, one per predicate. Each such specification proposes its predicate's characteristics for creation within a presentation.
The mandatory "name"
key maps to the name of the attribute.
The mandatory "cred_def_id"
key maps to the credential definition identifier of the credential with the current attribute. Note that since it is the holder who creates the preview and the holder possesses the corresponding credential, the holder must know its credential definition identifier.
The mandatory "predicate"
key maps to the predicate operator: "<"
, "<="
, ">="
, ">"
.
The mandatory "threshold"
key maps to the threshold value for the predicate.
Negotiation prior to the presentation can be done using the propose-presentation
and request-presentation
messages. A common negotiation use case would be about the data to go into the presentation. For that, the presentation-preview
element is used.
- VCX -- this implementation might not be perfect and needs to be improved, you can gather some info on parameters purpose from it
- A pre-RFC (labeled version 0.1) implementation of the protocol was implemented by a number of groups in the Hyperledger Indy community leading up to IIW28 in April 2019. The protocol can be found here. It was the basis of the IIWBook demo from BC Gov and collaborators.
The presentation preview as proposed above does not allow nesting of predicate logic along the lines of "A and either B or C if D, otherwise A and B", nor cross-credential-definition predicates such as proposing a legal name from either a financial institution or selected government entity.
The presentation preview may be indy-centric, as it assumes the inclusion of at most one credential per credential definition. In addition, it prescribes exactly four predicates and assumes mutual understanding of their semantics (e.g., could ">="
imply a lexicographic order for non-integer values, and if so, where to specify character collation algorithm?).
Finally, the inclusion of non-revocation timestamps may become desirable at the preview stage; the standard as proposed does not accommodate such.
- Why is this design the best in the space of possible designs?
- What other designs have been considered and what is the rationale for not choosing them?
- What is the impact of not doing this?
Similar (but simplified) credential exchange was already implemented in von-anchor.
- We might need some explicit documentation for nested
@type
fields. - There might need to be a way to associate a payment with the present proof protocol.
The following lists the implementations (if any) of this RFC. Please do a pull request to add your implementation. If the implementation is open source, include a link to the repo or to the implementation within the repo. Please be consistent in the "Name" field so that a mechanical processing of the RFCs can generate a list of all RFCs supported by an Aries implementation.
Name / Link | Implementation Notes |
---|---|
Streetcred.id | Commercial mobile and web app built using Aries Framework - .NET MISSING test results |