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}