credibil_vc/
dif_exch.rs

1//! # Distributed Identity Foundation Presentation Exchange
2//!
3//! Specifications:
4//! - <https://identity.foundation/presentation-exchange/spec/v2.0.0>
5//! - <https://identity.foundation/jwt-vc-presentation-profile>
6//! - <https://identity.foundation/claim-format-registry>
7
8pub mod matcher;
9
10use std::collections::HashMap;
11use std::str::FromStr;
12
13use serde::{Deserialize, Serialize};
14
15/// Used to provide `serde`-compatible set of Claims  serialized as JSON (as
16/// [`serde_json::Value`]).
17///
18/// Per the Presentation Exchange specification, this trait
19/// can be implemented for a variety of `Claim` formats.
20pub trait Claims {
21    /// Serialize Claims as a JSON object.
22    ///
23    /// # Errors
24    ///
25    /// The implementation should return an error if the Claims cannot be
26    /// serialized to JSON.
27    fn to_json(&self) -> anyhow::Result<serde_json::Value>;
28}
29
30/// A Presentation Definition is used by a Verifier to articulate proofs
31/// required. The proofs help the Verifier decide how to interact with the
32/// Holder providing the proofs.
33///
34/// <https://identity.foundation/presentation-exchange/spec/v2.0.0/#presentation-definition>
35#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
36pub struct PresentationDefinition {
37    /// A unique ID for the desired context. For example, a UUID is unique in a
38    /// global context, while a simple string could be suitably unique in a
39    /// local context.
40    pub id: String,
41
42    /// Input Descriptors describe the information a Verifier requires from the
43    /// Holder.
44    pub input_descriptors: Vec<InputDescriptor>,
45
46    /// If present, a human-friendly, distinctive designation for the
47    /// Presentation Definition.
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub name: Option<String>,
50
51    /// If present, it MUST describe the purpose for which the Presentation
52    /// Definition is being used for.
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub purpose: Option<String>,
55
56    /// One or more registered Claim Format Designation objects (e.g., `jwt`,
57    /// `jwt_vc`, `jwt_vp`, etc.). Used to inform the Holder of the Claim
58    /// formats the Verifier can process. For example,
59    ///
60    /// ```json
61    ///   "jwt": {
62    ///     "alg": ["EdDSA", "ES256K", "ES384"]
63    ///   },
64    /// ```
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub format: Option<HashMap<String, ClaimFormat>>,
67}
68
69/// Input Descriptors describe the information a Verifier requires from the
70/// Holder. All Input Descriptors MUST be satisfied, unless otherwise specified.
71#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
72pub struct InputDescriptor {
73    /// An identifier that does not conflict with the id of any other Input
74    /// Descriptor in the same Presentation Definition.
75    pub id: String,
76
77    /// If set, it SHOULD be a human-friendly name that describes what the
78    /// target schema represents.
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub name: Option<String>,
81
82    /// If present, its value MUST describe the purpose for which the Claim's
83    /// data is being requested.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub purpose: Option<String>,
86
87    /// If present, its MUST be an object with one or more properties matching
88    /// registered Claim Format Designations (e.g., `jwt`, `jwt_vc`, `jwt_vp`,
89    /// etc.). This property can be used to specifically constrain
90    /// submission of a single input to a subset of the top-level formats or
91    /// algorithms specified in the Presentation Definition.
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub format: Option<HashMap<String, ClaimFormat>>,
94
95    /// Contraints specify constraints on data values, and an explanation why a
96    /// certain item or set of data is being requested.
97    pub constraints: Constraints,
98}
99
100// TODO: create enum for ClaimFormat
101
102/// A registered Claim Format Designation object (e.g., `jwt`, `jwt_vc`,
103/// `jwt_vp`, etc.) used to inform the Holder of a Claim format the Verifier can
104/// process.
105///
106/// A Format object MUST include one of the format-specific properties (i.e.,
107/// `alg`, `proof_type`) that specify which algorithms the Verifier supports for
108/// the format.
109#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
110pub struct ClaimFormat {
111    /// An array of one or more algorithmic identifiers,
112    /// e.g. `["Ed2219", "ES256K"]`.
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub alg: Option<Vec<String>>,
115
116    /// An array of one or more proof type identifiers,
117    /// e.g. `["JsonWebSignature2020", "EcdsaSecp256k1Signature2019"]`.
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub proof_type: Option<Vec<String>>,
120}
121
122/// Contraints specify constraints on data values, and an explanation why a
123/// certain item or set of data is being requested.
124#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
125pub struct Constraints {
126    /// Fields are used to specify attributes of credential data the Verifier
127    /// requires. They are processed in order, meaning processing can be
128    /// reduced by checking the most defining characteristics of a
129    /// credential (e.g the type or schema of a credential) earlier.
130    /// Implementers SHOULD order field checks to ensure earliest termination of
131    /// evaluation.
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub fields: Option<Vec<Field>>,
134
135    ///If present, `limit_disclosure` MUST be one of the following strings:
136    /// "required" - indicates that the Conformant Consumer MUST limit submitted
137    /// fields  to those listed in the fields array (if present). Conformant
138    /// Consumers are not required  to implement support for this value, but
139    /// they MUST understand this value sufficiently  to return nothing (or
140    /// cease the interaction with the Verifier) if they do not implement it.
141    ///
142    /// "preferred" - indicates that the Conformant Consumer SHOULD limit
143    /// submitted fields to those listed in the fields array (if present).
144    ///
145    /// Omission of this property indicates the Conformant Consumer MAY submit a
146    /// response that contains more than the data described in the fields
147    /// array.
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub limit_disclosure: Option<String>,
150}
151
152/// Fields are used to specify attributes of credential data the Verifier
153/// requires.
154/// See <https://identity.foundation/presentation-exchange/spec/v2.0.0/#presentation-definition-in-an-envelope>
155#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
156pub struct Field {
157    /// If present, it MUST be unique from every other field object’s id
158    /// property, including those contained in other Input Descriptor
159    /// Objects.
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub id: Option<String>,
162
163    /// One or more `JSONPath` expressions that select a target value from the
164    /// input. The array MUST be evaluated in order, breaking as soon as a
165    /// Field Query Result is found. The ability to use multiple expressions
166    /// allows the Verifier to account for differences in credential
167    /// formats.
168    /// see <https://identity.foundation/presentation-exchange/spec/v2.0.0/#jsonpath-syntax-definition>
169    pub path: Vec<String>,
170
171    /// If present, it MUST be a JSON Schema descriptor used to filter against
172    /// the values returned from evaluation of the `JSONPath` expressions in
173    /// the path array.
174    #[serde(skip_serializing_if = "Option::is_none")]
175    pub filter: Option<Filter>,
176
177    /// The predicate Feature enables the Verifier to request that Wallet apply
178    /// a predicate and return a boolean rather than the matching
179    /// credential.
180    ///
181    /// If `predicate` is present:
182    ///  - it MUST be one of "required" or "preferred"
183    ///  - the `filter` field containing the predicate MUST also be present.
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub predicate: Option<String>,
186
187    /// If present, its MUST describe the purpose for which the field is being
188    /// requested.
189    #[serde(skip_serializing_if = "Option::is_none")]
190    pub purpose: Option<String>,
191
192    /// If present, it SHOULD be a human-friendly name that describes what the
193    /// target field represents.
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub name: Option<String>,
196
197    /// If present, it MUST indicate whether the field is optional or not.
198    /// Defaults to false. Even when set to `true`, the path value MUST
199    /// validate against the JSON Schema filter, if a filter is present.
200    #[serde(skip_serializing_if = "Option::is_none")]
201    pub optional: Option<bool>,
202
203    /// If present, MUST be a boolean that indicates the Verifier intends to
204    /// retain the Claim's data being requested.
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub intent_to_retain: Option<bool>,
207}
208
209/// A JSON Schema descriptor used to filter against the values returned from
210/// evaluation of the `JSONPath` expressions in the path array.
211#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
212#[serde(deny_unknown_fields)]
213pub struct Filter {
214    /// The type of filter to apply.
215    #[serde(rename = "type")]
216    pub type_: String,
217
218    /// The value of the filter to apply.
219    #[serde(flatten)]
220    pub value: FilterValue,
221}
222
223/// `FilterValue` represents the type and value of a `JSONPath` filter.
224#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
225#[serde(rename_all = "snake_case")]
226pub enum FilterValue {
227    /// The value of the filter is a constant.
228    Const(String),
229
230    /// The value of the filter is a regular expression.
231    Pattern(String),
232
233    /// The value of the filter is a JSON Schema type format. For example,
234    /// "date-time".
235    Format(String),
236}
237
238impl Default for FilterValue {
239    fn default() -> Self {
240        Self::Const(String::new())
241    }
242}
243
244/// A Presentation Submission expresses how proofs presented to the Verifier, in
245/// accordance with the requirements specified in a Presentation Definition.
246///
247/// <https://identity.foundation/presentation-exchange/spec/v2.0.0/#presentation-submission>
248#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
249pub struct PresentationSubmission {
250    /// The `id` MUST be a unique identifier, such as a UUID.
251    pub id: String,
252
253    /// The value of this property MUST be the id value of the Presentation
254    /// Definition this submission fulfills.
255    pub definition_id: String,
256
257    /// An array of Input Descriptor Mapping Objects.
258    pub descriptor_map: Vec<DescriptorMap>,
259}
260
261impl FromStr for PresentationSubmission {
262    type Err = anyhow::Error;
263
264    fn from_str(s: &str) -> anyhow::Result<Self, Self::Err> {
265        Ok(serde_json::from_str::<Self>(s)?)
266    }
267}
268
269/// An Input Descriptor Mapping Object is used to map an Input Descriptor to a
270/// Verifiable Credential or a JSON Web Token.
271#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
272pub struct DescriptorMap {
273    /// MUST match the Input Descriptor id in the Presentation Definition this
274    /// Presentation Submission is related to.
275    pub id: String,
276
277    /// Denotes the data format of the Claim. MUST match one of the Claim Format
278    /// Designations specified in the Input Descriptor.
279    pub format: String,
280
281    /// A `JSONPath` string expression that indicates the Claim submitted in
282    /// relation to the Input Descriptor, when executed against the
283    /// top-level of the object the Presentation Submission.
284    /// For the `OpenID4VP` specification, this value MUST be:
285    ///  - $ when only one Verifiable Presentation
286    ///  - $\[n\] when there are multiple Verifiable Presentations, where n is
287    ///    the vp's index.
288    pub path: String,
289
290    /// Refers to the actual Credential carried in the respective Verifiable
291    /// Presentation. Used to describe how to find a returned Credential
292    /// within a Verifiable Presentation.
293    pub path_nested: PathNested, // Option<Box<DescriptorMap>>,
294}
295
296/// A nested path object is used to describe how to find a returned Credential
297/// within the Verifiable Presentation.
298#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
299pub struct PathNested {
300    /// Format of the credential returned in the Verifiable Presentation.
301    pub format: String,
302
303    /// Describes how to find a returned Credential within a Verifiable
304    /// Presentation. The value depends on the credential format.
305    pub path: String,
306}