1use bbs::{ProofNonce, SignatureProof, ToVariableLengthBytes};
18use serde::{Deserialize, Serialize};
19use std::collections::HashMap;
20
21pub const CREDENTIAL_REQUEST_TYPE: &str = "EvanBbsCredentialRequest";
22pub const CREDENTIAL_PROPOSAL_TYPE: &str = "EvanCredentialProposal";
23pub const CREDENTIAL_OFFER_TYPE: &str = "EvanBbsCredentialOffering";
24pub const CREDENTIAL_SIGNATURE_TYPE: &str = "BbsBlsSignature2020";
25pub const PROOF_SIGNATURE_TYPE: &str = "BbsBlsSignatureProof2020";
26pub const CREDENTIAL_SCHEMA_TYPE: &str = "EvanZKPSchema";
27pub const CREDENTIAL_PROOF_PURPOSE: &str = "assertionMethod";
28pub const DEFAULT_CREDENTIAL_CONTEXTS: [&'static str; 3] = [
29 "https://www.w3.org/2018/credentials/v1",
30 "https://schema.org",
31 "https://w3id.org/vc-revocation-list-2020/v1",
32];
33pub const DEFAULT_REVOCATION_CONTEXTS: [&'static str; 2] = [
34 "https://www.w3.org/2018/credentials/v1",
35 "https://w3id.org/vc-revocation-list-2020/v1",
36];
37
38pub const BBS_PROOF_TYPE: &str = "BBS";
39
40#[derive(Serialize, Deserialize, Clone)]
44#[serde(rename_all = "camelCase")]
45pub struct BbsCredentialRequest {
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub subject: Option<String>,
48 pub schema: String,
49 pub r#type: String,
50 pub blind_signature_context: String,
51 pub credential_values: HashMap<String, String>,
52}
53
54#[derive(Serialize, Deserialize, Clone)]
56#[serde(rename_all = "camelCase")]
57pub struct BbsProofRequest {
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub verifier: Option<String>,
60 pub created_at: String,
61 pub nonce: String,
62 pub r#type: String,
63 pub sub_proof_requests: Vec<BbsSubProofRequest>,
64}
65
66#[derive(Serialize, Deserialize, Clone)]
68#[serde(rename_all = "camelCase")]
69pub struct BbsSubProofRequest {
70 pub schema: String,
71 pub revealed_attributes: Vec<usize>,
72}
73
74#[derive(Serialize, Deserialize, Clone)]
77#[serde(rename_all = "camelCase")]
78pub struct CredentialSchema {
79 pub id: String,
80 pub r#type: String,
81 pub name: String,
82 pub author: String,
83 pub created_at: String,
84 pub description: String,
85 pub properties: HashMap<String, SchemaProperty>,
86 pub required: Vec<String>,
87 pub additional_properties: bool,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub proof: Option<AssertionProof>,
90}
91
92#[derive(Serialize, Deserialize, Clone)]
94#[serde(rename_all = "camelCase")]
95pub struct SchemaProperty {
96 pub r#type: String,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub format: Option<String>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub items: Option<Vec<String>>,
101}
102
103#[derive(Serialize, Deserialize, Clone)]
105#[serde(rename_all = "camelCase")]
106pub struct AssertionProof {
107 pub r#type: String,
108 pub created: String,
109 pub proof_purpose: String,
110 pub verification_method: String,
111 pub jws: String,
112}
113
114#[derive(Serialize, Deserialize, Clone)]
118#[serde(rename_all = "camelCase")]
119pub struct BbsCredentialOffer {
120 pub issuer: String,
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub subject: Option<String>,
123 pub nonce: String,
124 pub credential_message_count: usize,
125}
126
127#[derive(Serialize, Deserialize, Clone)]
130#[serde(rename_all = "camelCase")]
131pub struct CredentialProposal {
132 pub issuer: String,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub subject: Option<String>,
135 pub r#type: String,
136 pub schema: String,
137}
138
139#[derive(Serialize, Deserialize, Clone)]
143#[serde(rename_all = "camelCase")]
144pub struct BbsCredential {
145 #[serde(rename(serialize = "@context", deserialize = "@context"))]
146 pub context: Vec<String>,
147 pub id: String,
148 pub r#type: Vec<String>,
149 pub issuer: String,
150 pub issuance_date: String,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub valid_until: Option<String>,
153 pub credential_subject: CredentialSubject,
154 pub credential_schema: CredentialSchemaReference,
155 pub credential_status: CredentialStatus,
156 pub proof: BbsCredentialSignature,
157}
158
159impl BbsCredential {
160 pub fn new(cred: UnfinishedBbsCredential, signature: String) -> BbsCredential {
161 BbsCredential {
162 context: cred.context,
163 id: cred.id,
164 r#type: cred.r#type,
165 issuer: cred.issuer,
166 issuance_date: cred.issuance_date,
167 valid_until: cred.valid_until,
168 credential_subject: CredentialSubject {
169 id: cred.credential_subject.id,
170 data: cred.credential_subject.data,
171 },
172 credential_schema: CredentialSchemaReference {
173 id: cred.credential_schema.id,
174 r#type: cred.credential_schema.r#type,
175 },
176 credential_status: CredentialStatus {
177 id: cred.credential_status.id,
178 r#type: cred.credential_status.r#type,
179 revocation_list_index: cred.credential_status.revocation_list_index,
180 revocation_list_credential: cred.credential_status.revocation_list_credential,
181 },
182 proof: BbsCredentialSignature {
183 created: cred.proof.created,
184 proof_purpose: cred.proof.proof_purpose,
185 required_reveal_statements: cred.proof.required_reveal_statements,
186 signature: signature,
187 credential_message_count: cred.proof.credential_message_count,
188 r#type: cred.proof.r#type,
189 verification_method: cred.proof.verification_method,
190 },
191 }
192 }
193}
194
195#[derive(Serialize, Deserialize, Clone)]
197#[serde(rename_all = "camelCase")]
198pub struct UnsignedBbsCredential {
199 #[serde(rename(serialize = "@context", deserialize = "@context"))]
200 pub context: Vec<String>,
201 pub id: String,
202 pub r#type: Vec<String>,
203 pub issuer: String,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub valid_until: Option<String>,
206 pub issuance_date: String,
207 pub credential_subject: CredentialSubject,
208 pub credential_schema: CredentialSchemaReference,
209 pub credential_status: CredentialStatus,
210}
211
212#[derive(Serialize, Deserialize, Clone)]
214#[serde(rename_all = "camelCase")]
215pub struct UnfinishedBbsCredential {
216 #[serde(rename(serialize = "@context", deserialize = "@context"))]
217 pub context: Vec<String>,
218 pub id: String,
219 pub r#type: Vec<String>,
220 pub issuer: String,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub valid_until: Option<String>,
223 pub issuance_date: String,
224 pub credential_subject: CredentialSubject,
225 pub credential_schema: CredentialSchemaReference,
226 pub credential_status: CredentialStatus,
227 pub proof: UnfinishedBbsCredentialSignature,
228}
229
230impl UnfinishedBbsCredential {
231 pub fn new(
232 unsigned_vc: UnsignedBbsCredential,
233 signature: UnfinishedBbsCredentialSignature,
234 ) -> UnfinishedBbsCredential {
235 UnfinishedBbsCredential {
236 context: unsigned_vc.context,
237 id: unsigned_vc.id,
238 r#type: unsigned_vc.r#type,
239 issuer: unsigned_vc.issuer,
240 valid_until: unsigned_vc.valid_until,
241 issuance_date: unsigned_vc.issuance_date,
242 credential_schema: unsigned_vc.credential_schema,
243 credential_subject: unsigned_vc.credential_subject,
244 credential_status: unsigned_vc.credential_status,
245 proof: signature,
246 }
247 }
248}
249
250#[derive(Serialize, Deserialize, Clone, Debug)]
252#[serde(rename_all = "camelCase")]
253pub struct CredentialSubject {
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub id: Option<String>,
256 pub data: HashMap<String, String>,
257}
258
259#[derive(Serialize, Deserialize, Clone)]
261#[serde(rename_all = "camelCase")]
262pub struct CredentialStatus {
263 pub id: String,
264 pub r#type: String,
265 pub revocation_list_index: String,
266 pub revocation_list_credential: String,
267}
268
269#[derive(Serialize, Deserialize, Clone)]
271#[serde(rename_all = "camelCase")]
272pub struct RevocationListCredentialSubject {
273 pub id: String,
274 pub r#type: String,
275 pub encoded_list: String,
276}
277
278#[derive(Serialize, Deserialize, Clone)]
280#[serde(rename_all = "camelCase")]
281pub struct CredentialSchemaReference {
282 pub id: String,
283 pub r#type: String,
284}
285
286#[derive(Serialize, Deserialize, Clone)]
288#[serde(rename_all = "camelCase")]
289pub struct BbsCredentialSignature {
290 pub r#type: String,
291 pub created: String,
292 pub proof_purpose: String,
293 pub verification_method: String,
294 pub credential_message_count: usize,
295 pub required_reveal_statements: Vec<u32>,
296 pub signature: String,
297}
298
299#[derive(Serialize, Deserialize, Clone)]
302#[serde(rename_all = "camelCase")]
303pub struct UnfinishedBbsCredentialSignature {
304 pub r#type: String,
305 pub created: String,
306 pub proof_purpose: String,
307 pub verification_method: String,
308 pub credential_message_count: usize,
309 pub required_reveal_statements: Vec<u32>,
310 pub blind_signature: String,
311}
312
313#[derive(Serialize, Deserialize, Clone)]
316#[serde(rename_all = "camelCase")]
317pub struct ProofPresentation {
318 #[serde(rename(serialize = "@context", deserialize = "@context"))]
319 pub context: Vec<String>,
320 pub id: String,
321 pub r#type: Vec<String>,
322 pub verifiable_credential: Vec<BbsPresentation>,
323 pub proof: AssertionProof,
324}
325
326impl ProofPresentation {
327 pub fn new(
328 unsigned_proof_presentation: UnfinishedProofPresentation,
329 proof: AssertionProof,
330 ) -> ProofPresentation {
331 return ProofPresentation {
332 context: unsigned_proof_presentation.context,
333 id: unsigned_proof_presentation.id,
334 r#type: unsigned_proof_presentation.r#type,
335 verifiable_credential: unsigned_proof_presentation.verifiable_credential,
336 proof: proof,
337 };
338 }
339}
340
341#[derive(Serialize, Deserialize)]
343#[serde(rename_all = "camelCase")]
344pub struct UnfinishedProofPresentation {
345 #[serde(rename(serialize = "@context", deserialize = "@context"))]
346 pub context: Vec<String>,
347 pub id: String,
348 pub r#type: Vec<String>,
349 pub verifiable_credential: Vec<BbsPresentation>,
350}
351
352#[derive(Serialize, Deserialize, Clone)]
354#[serde(rename_all = "camelCase")]
355pub struct BbsPresentation {
356 #[serde(rename(serialize = "@context", deserialize = "@context"))]
357 pub context: Vec<String>,
358 pub id: String,
359 pub r#type: Vec<String>,
360 pub issuer: String,
361 pub issuance_date: String,
362 pub credential_subject: CredentialSubject,
363 pub credential_schema: CredentialSchemaReference,
364 pub credential_status: CredentialStatus,
365 pub proof: BbsPresentationProof,
366}
367
368impl BbsPresentation {
369 pub fn new(
370 cred: BbsCredential,
371 issuance_date: String,
372 proof: SignatureProof,
373 revealed_properties: CredentialSubject,
374 nonce: ProofNonce,
375 ) -> BbsPresentation {
376 BbsPresentation {
377 context: cred.context,
378 id: cred.id,
379 issuance_date: issuance_date,
380 r#type: cred.r#type,
381 issuer: cred.issuer,
382 credential_subject: revealed_properties,
383 credential_schema: CredentialSchemaReference {
384 id: cred.credential_schema.id,
385 r#type: cred.credential_schema.r#type,
386 },
387 credential_status: CredentialStatus {
388 id: cred.credential_status.id,
389 r#type: cred.credential_status.r#type,
390 revocation_list_index: cred.credential_status.revocation_list_index,
391 revocation_list_credential: cred.credential_status.revocation_list_credential,
392 },
393 proof: BbsPresentationProof {
394 created: cred.proof.created,
395 proof_purpose: cred.proof.proof_purpose,
396 proof: base64::encode(proof.to_bytes_compressed_form()),
397 credential_message_count: cred.proof.credential_message_count,
398 r#type: PROOF_SIGNATURE_TYPE.to_owned(),
399 verification_method: cred.proof.verification_method,
400 nonce: base64::encode(nonce.to_bytes_compressed_form()),
401 },
402 }
403 }
404}
405
406#[derive(Serialize, Deserialize, Clone)]
408#[serde(rename_all = "camelCase")]
409pub struct BbsPresentationProof {
410 pub r#type: String,
411 pub created: String,
412 pub proof_purpose: String,
413 pub credential_message_count: usize,
414 pub verification_method: String,
415 pub nonce: String,
416 pub proof: String,
417}
418
419#[derive(Serialize, Deserialize)]
422#[serde(rename_all = "camelCase")]
423pub struct BbsProofVerification {
424 pub presented_proof: String,
425 pub status: String,
426 #[serde(skip_serializing_if = "Option::is_none")]
427 pub reason: Option<String>,
428}
429
430#[derive(Serialize, Deserialize, Clone)]
432#[serde(rename_all = "camelCase")]
433pub struct UnproofedRevocationListCredential {
434 #[serde(rename(serialize = "@context", deserialize = "@context"))]
435 pub context: Vec<String>,
436 pub id: String,
437 pub r#type: Vec<String>,
438 pub issuer: String,
439 pub issued: String,
440 pub credential_subject: RevocationListCredentialSubject,
441}
442
443#[derive(Serialize, Deserialize, Clone)]
446#[serde(rename_all = "camelCase")]
447pub struct RevocationListCredential {
448 #[serde(rename(serialize = "@context", deserialize = "@context"))]
449 pub context: Vec<String>,
450 pub id: String,
451 pub r#type: Vec<String>,
452 pub issuer: String,
453 pub issued: String,
454 pub credential_subject: RevocationListCredentialSubject,
455 pub proof: AssertionProof,
456}
457
458impl RevocationListCredential {
459 pub fn new(
460 list: UnproofedRevocationListCredential,
461 proof: AssertionProof,
462 ) -> RevocationListCredential {
463 RevocationListCredential {
464 context: list.context,
465 id: list.id,
466 r#type: list.r#type,
467 issuer: list.issuer,
468 issued: list.issued,
469 credential_subject: list.credential_subject,
470 proof,
471 }
472 }
473}