1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
//! The specification vectors the tests of this crate run against (feature `test-vectors`), so
//! that a crate building on this one can test against the same examples: RFC 9901 (SD-JWT),
//! SD-JWT VC, the Token Status List, VC-JOSE-COSE presentations, the DIF Well Known DID
//! Configuration and DIF Linked Verifiable Presentation.
//!
//! Every constant is the text of the specification's example exactly as published, with a
//! trailing newline; a compact token is one line, call `trim` before parsing it. The JOSE,
//! DID and W3C VC examples the tests also use are short enough to live inline in the tests,
//! and are not repeated here.
//!
//! ```
//! use identity_kit::sd_jwt_vc::SdJwt;
//! use identity_kit::vectors::sd_jwt::simple;
//!
//! let issuance = SdJwt::parse(simple::ISSUANCE.trim())?;
//! assert_eq!(issuance.disclosures().len(), simple::DISCLOSURES.lines().count());
//! # Ok::<(), identity_kit::sd_jwt_vc::SdJwtError>(())
//! ```
macro_rules! vectors {
($($(#[$doc:meta])* $name:ident = $path:literal;)*) => {
$(
$(#[$doc])*
pub const $name: &str = include_str!(concat!("../tests/vectors/", $path));
)*
};
}
/// RFC 9901 (SD-JWT), all signed with the issuer key of Appendix A.5.
pub mod sd_jwt {
/// §5: the simple example, issued and presented with key binding.
pub mod simple {
vectors! {
/// The issuer's claims before selective disclosure.
USER_CLAIMS = "sd_jwt/simple/user_claims.json";
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/simple/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/simple/disclosures.txt";
/// The issuer-signed JWT alone.
JWS = "sd_jwt/simple/jws.txt";
/// The SD-JWT as issued.
ISSUANCE = "sd_jwt/simple/issuance.txt";
/// The presentation with key binding.
PRESENTATION = "sd_jwt/simple/presentation.txt";
/// The payload of the key binding JWT.
KB_PAYLOAD = "sd_jwt/simple/kb_payload.json";
/// The claims the verifier obtains from the presentation.
VERIFIED = "sd_jwt/simple/verified.json";
}
}
/// §6.1: a flat SD-JWT, `address` disclosable as a whole.
pub mod flat {
vectors! {
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/flat/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/flat/disclosures.txt";
}
}
/// §6.2: a structured SD-JWT, the members of `address` disclosable one by one.
pub mod structured {
vectors! {
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/structured/payload.json";
/// The payload with `country` always disclosed.
PAYLOAD_ONE_OPEN = "sd_jwt/structured/payload_one_open.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/structured/disclosures.txt";
}
}
/// §6.3: recursive disclosures, `address` and its members disclosable.
pub mod recursive {
vectors! {
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/recursive/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/recursive/disclosures.txt";
}
}
/// Appendix A.1: a simple structured SD-JWT with decoy digests.
pub mod simple_structured {
vectors! {
/// The issuer's claims before selective disclosure.
USER_CLAIMS = "sd_jwt/simple_structured/user_claims.json";
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/simple_structured/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/simple_structured/disclosures.txt";
/// The decoy digests, one per line.
DECOYS = "sd_jwt/simple_structured/decoys.txt";
/// The presentation.
PRESENTATION = "sd_jwt/simple_structured/presentation.txt";
/// The claims the verifier obtains from the presentation.
VERIFIED = "sd_jwt/simple_structured/verified.json";
}
}
/// Appendix A.2: the complex structured eKYC example.
pub mod complex_ekyc {
vectors! {
/// The issuer's claims before selective disclosure.
USER_CLAIMS = "sd_jwt/complex_ekyc/user_claims.json";
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/complex_ekyc/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/complex_ekyc/disclosures.txt";
/// The presentation.
PRESENTATION = "sd_jwt/complex_ekyc/presentation.txt";
/// The claims the verifier obtains from the presentation.
VERIFIED = "sd_jwt/complex_ekyc/verified.json";
}
}
/// Appendix A.3: an SD-JWT-based verifiable credential.
pub mod sd_jwt_vc {
vectors! {
/// The issuer's claims before selective disclosure.
USER_CLAIMS = "sd_jwt/sd_jwt_vc/user_claims.json";
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/sd_jwt_vc/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/sd_jwt_vc/disclosures.txt";
/// The SD-JWT as issued.
ISSUANCE = "sd_jwt/sd_jwt_vc/issuance.txt";
/// The presentation with key binding.
PRESENTATION = "sd_jwt/sd_jwt_vc/presentation.txt";
/// The payload of the key binding JWT.
KB_PAYLOAD = "sd_jwt/sd_jwt_vc/kb_payload.json";
/// The claims the verifier obtains from the presentation.
VERIFIED = "sd_jwt/sd_jwt_vc/verified.json";
}
}
/// Appendix A.4: a W3C Verifiable Credentials Data Model credential.
pub mod w3c_vcdm {
vectors! {
/// The issuer's claims before selective disclosure.
USER_CLAIMS = "sd_jwt/w3c_vcdm/user_claims.json";
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt/w3c_vcdm/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt/w3c_vcdm/disclosures.txt";
/// The SD-JWT as issued.
ISSUANCE = "sd_jwt/w3c_vcdm/issuance.txt";
/// The presentation with key binding.
PRESENTATION = "sd_jwt/w3c_vcdm/presentation.txt";
/// The claims the verifier obtains from the presentation.
VERIFIED = "sd_jwt/w3c_vcdm/verified.json";
}
}
}
/// SD-JWT VC: the credentials of §2.3 and Appendix A.1.
pub mod sd_jwt_vc {
/// §2.3: the identity credential, issued and presented with and without key binding.
pub mod identity_credential {
vectors! {
/// The issuer's claims before selective disclosure.
USER_CLAIMS = "sd_jwt_vc/identity_credential/user_claims.json";
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt_vc/identity_credential/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt_vc/identity_credential/disclosures.txt";
/// The SD-JWT VC as issued.
ISSUANCE = "sd_jwt_vc/identity_credential/issuance.txt";
/// The presentation with key binding.
PRESENTATION = "sd_jwt_vc/identity_credential/presentation.txt";
/// The claims the verifier obtains from the presentation with key binding.
VERIFIED = "sd_jwt_vc/identity_credential/verified.json";
/// The presentation without key binding.
PRESENTATION_NO_KB = "sd_jwt_vc/identity_credential/presentation_no_kb.txt";
/// The claims the verifier obtains from the presentation without key binding.
VERIFIED_NO_KB = "sd_jwt_vc/identity_credential/verified_no_kb.json";
}
}
/// Appendix A.1: the person identification data (PID) credential.
pub mod pid {
vectors! {
/// The payload of the issuer-signed JWT.
PAYLOAD = "sd_jwt_vc/pid/payload.json";
/// The disclosures, one per line.
DISCLOSURES = "sd_jwt_vc/pid/disclosures.txt";
/// The SD-JWT VC as issued.
ISSUANCE = "sd_jwt_vc/pid/issuance.txt";
/// The presentation with key binding.
PRESENTATION = "sd_jwt_vc/pid/presentation.txt";
/// The payload of the key binding JWT.
KB_PAYLOAD = "sd_jwt_vc/pid/kb_payload.json";
/// The claims the verifier obtains from the presentation.
VERIFIED = "sd_jwt_vc/pid/verified.json";
}
}
}
/// SD-JWT VC type metadata (SD-JWT VC §5 and Appendix A.2).
pub mod type_metadata {
vectors! {
/// §5.1: the type metadata document of the education credential, version 42.
EDUCATION_CREDENTIAL_V42 = "type_metadata/education_credential_v42.json";
/// Appendix A.2: the education credential's type metadata with display and claim
/// metadata.
EDUCATION_CREDENTIAL = "type_metadata/education_credential.json";
/// §5.6.1: the credential payload the claim path examples select from.
PAYLOAD = "type_metadata/payload.json";
}
}
/// The Token Status List.
pub mod status_list {
vectors! {
/// §4.1: a list of 16 one-bit statuses.
LIST_1BIT = "status_list/list_1bit.json";
/// §4.2: a list of 12 two-bit statuses.
LIST_2BIT = "status_list/list_2bit.json";
/// §5: the status list token as a JWT.
TOKEN = "status_list/token.txt";
/// §5: the header of the status list token.
TOKEN_HEADER = "status_list/token_header.json";
/// §5: the payload of the status list token.
TOKEN_PAYLOAD = "status_list/token_payload.json";
/// §6: the header of the referenced token.
REFERENCED_HEADER = "status_list/referenced_header.json";
/// §6.2: the payload of a referenced token, with its `status` claim.
REFERENCED_PAYLOAD = "status_list/referenced_payload.json";
/// §6.2: an SD-JWT carrying the `status` claim.
REFERENCED_SD_JWT = "status_list/referenced_sd_jwt.txt";
/// §6.2: the processed payload of that SD-JWT.
REFERENCED_PROCESSED = "status_list/referenced_processed.json";
/// Appendix C.1: a one-bit status list.
C1_1BIT = "status_list/c1_1bit.json";
/// Appendix C.1: the statuses of the one-bit list, by index.
C1_1BIT_STATUSES = "status_list/c1_1bit_statuses.json";
/// Appendix C.2: a two-bit status list.
C2_2BIT = "status_list/c2_2bit.json";
/// Appendix C.2: the statuses of the two-bit list, by index.
C2_2BIT_STATUSES = "status_list/c2_2bit_statuses.json";
/// Appendix C.3: a four-bit status list.
C3_4BIT = "status_list/c3_4bit.json";
/// Appendix C.3: the statuses of the four-bit list, by index.
C3_4BIT_STATUSES = "status_list/c3_4bit_statuses.json";
/// Appendix C.4: an eight-bit status list.
C4_8BIT = "status_list/c4_8bit.json";
/// Appendix C.4: the statuses of the eight-bit list, by index.
C4_8BIT_STATUSES = "status_list/c4_8bit_statuses.json";
}
}
/// VC-JOSE-COSE: VCDM 2.0 presentations secured with JOSE (`vp+jwt`) and credentials secured
/// with SD-JWT (`vc+sd-jwt`).
pub mod vc_jose_cose {
vectors! {
/// W3C VC-JOSE-COSE test suite input `credential-selective.json`: the credential of
/// [`SUITE_CREDENTIAL_SDJWT_SELECTIVE`] before securing.
SUITE_CREDENTIAL_SELECTIVE = "vc_jose_cose/suite-credential-selective.json";
/// W3C VC-JOSE-COSE test suite input `credential-sdjwt-selective.txt` (test 20), a
/// `vc+sd-jwt` with `credentialSubject.firstName` and `lastName` selectively
/// disclosable, signed with [`SUITE_VM_P384`].
SUITE_CREDENTIAL_SDJWT_SELECTIVE = "vc_jose_cose/suite-credential-sdjwt-selective.txt";
/// W3C VC-JOSE-COSE test suite input `credential-nested-selective.json`: the credential
/// of [`SUITE_CREDENTIAL_SDJWT_NESTED`] before securing.
SUITE_CREDENTIAL_NESTED_SELECTIVE = "vc_jose_cose/suite-credential-nested-selective.json";
/// W3C VC-JOSE-COSE test suite input `credential-sdjwt-nested.txt` (test 21), a
/// `vc+sd-jwt` with nested properties and an array element selectively disclosable,
/// signed with [`SUITE_VM_P521`].
SUITE_CREDENTIAL_SDJWT_NESTED = "vc_jose_cose/suite-credential-sdjwt-nested.txt";
/// W3C VC-JOSE-COSE test suite input `credential-sdjwt-bad-signature.txt` (test 23):
/// [`SUITE_CREDENTIAL_SDJWT_SELECTIVE`] with its signature bytes rearranged.
SUITE_CREDENTIAL_SDJWT_BAD_SIGNATURE = "vc_jose_cose/suite-credential-sdjwt-bad-signature.txt";
/// W3C VC-JOSE-COSE test suite input `credential-sdjwt-bad-media-type.txt` (test 24),
/// `typ` `bad+typ`, signed with [`SUITE_VM_ED25519`].
SUITE_CREDENTIAL_SDJWT_BAD_MEDIA_TYPE = "vc_jose_cose/suite-credential-sdjwt-bad-media-type.txt";
/// The `vp+jwt` of the specification's "verifiable presentation secured with JOSE with
/// the `EnvelopedVerifiablePresentation` type" example, as its `data:` URL holds it.
ENVELOPED_PRESENTATION_JWT = "vc_jose_cose/enveloped_presentation_jwt.txt";
/// W3C VC-JOSE-COSE test suite input `presentation-jose-multiple.txt` (test 7), signed
/// with [`SUITE_VM_P384`]: a `vc+jwt`, an SD-JWT and a COSE credential enveloped.
SUITE_PRESENTATION_MULTIPLE = "vc_jose_cose/suite-presentation-jose-multiple.txt";
/// W3C VC-JOSE-COSE test suite input `presentation-jose-bad-media-type.txt` (test 14),
/// `typ` `bad+typ`, signed with [`SUITE_VM_ED25519`].
SUITE_PRESENTATION_BAD_MEDIA_TYPE = "vc_jose_cose/suite-presentation-jose-bad-media-type.txt";
/// W3C VC-JOSE-COSE test suite input `presentation-jose-bad-credential.txt` (test 16),
/// an envelope whose `id` is not a `data:` URL, signed with [`SUITE_VM_ED25519`].
SUITE_PRESENTATION_BAD_CREDENTIAL = "vc_jose_cose/suite-presentation-jose-bad-credential.txt";
/// The test suite's P-256 verification method (`vm-p256.json`, public part).
SUITE_VM_P256 = "vc_jose_cose/suite-vm-p256.json";
/// The test suite's P-384 verification method (`vm-p384.json`, public part).
SUITE_VM_P384 = "vc_jose_cose/suite-vm-p384.json";
/// The test suite's Ed25519 verification method (`vm-ed25519.json`, public part).
SUITE_VM_ED25519 = "vc_jose_cose/suite-vm-ed25519.json";
/// The test suite's P-521 verification method (`vm-p521.json`, public part).
SUITE_VM_P521 = "vc_jose_cose/suite-vm-p521.json";
}
}
/// DIF Well Known DID Configuration: the example resource and its credentials, and the example
/// DID document with `LinkedDomains` services.
pub mod did_configuration {
vectors! {
/// The example DID configuration resource, with a Linked Data Proof entry and a JSON
/// Web Token entry.
RESOURCE = "did_configuration/resource.json";
/// The Linked Data Proof entry of the resource.
LINKED_DATA_CREDENTIAL = "did_configuration/linked_data_credential.json";
/// The JSON Web Token entry of the resource.
JWT = "did_configuration/jwt.txt";
/// The header of that JWT.
HEADER = "did_configuration/header.json";
/// The payload of that JWT.
PAYLOAD = "did_configuration/payload.json";
/// The example DID document with two `LinkedDomains` services, one listing two origins
/// in an `origins` object, one a single origin string.
DID_DOCUMENT = "did_configuration/did_document.json";
}
}
/// DIF Linked Verifiable Presentation v1.0.0: the example DID documents and presentations.
pub mod linked_vp {
vectors! {
/// The example DID document with an HTTPS and an IPFS `LinkedVerifiablePresentation`
/// service.
DID_DOCUMENT = "linked_vp/did_document.json";
/// The same document with hashlink-protected URLs (Security Considerations).
DID_DOCUMENT_HASHLINKS = "linked_vp/did_document_hashlinks.json";
/// The example presentation in the JSON Web Token form, one credential JWT inside.
JWT = "linked_vp/jwt.txt";
/// The header of that JWT, `typ` the literal `'vp+ld+jwt'`.
HEADER = "linked_vp/header.json";
/// The header of the credential JWT inside, `typ` the literal `'vc+ld+jwt'`.
CREDENTIAL_HEADER = "linked_vp/credential_header.json";
/// The example presentation in the JSON-LD form.
JSON_LD = "linked_vp/presentation.jsonld";
/// The presentation the specification repository's generator wrote with the
/// presentation members at the top level of the payload rather than in `vp`, which
/// the specification's "decoded JWT payload" example shows.
FLAT_JWT = "linked_vp/flat_jwt.txt";
/// The verification method that signed [`JWT`] and [`FLAT_JWT`], from the
/// specification repository's generator
/// (`resources/linked-vp/generate-config/keys/did-key-ed25519.json`, public part).
/// The example DID document shows another key, which verifies neither.
VERIFICATION_METHOD = "linked_vp/verification_method.json";
}
}