vade_evan_bbs/application/
datatypes.rs

1/*
2  Copyright (c) 2018-present evan GmbH.
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15*/
16
17use 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/// Message following a `BbsCredentialOffer`, sent by a potential credential prover.
41/// Provides the values that need to be signed by the issuer in both encoded/cleartext, and blinded format.
42/// Incorporates the nonce value sent in `BbsCredentialOffer`.
43#[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/// Message sent by a verifier stating which attributes of which schema the prover is supposed to reveal.
55#[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/// Part of a proof request that requests attributes of a specific schema
67#[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/// Specifies the properties of a credential, as well as metadata.
75/// Needs to be stored publicly available and temper-proof.
76#[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/// Metadata about a property of a credential schema
93#[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/// AssertionProof, typically used to ensure authenticity and integrity of a verifiable credential
104#[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/// Message following a `CredentialProposal`, sent by an issuer.
115/// Specifies the DIDs of both the `CredentialSchema` and `CredentialDefinition`
116/// to be used for issuance.
117#[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/// Message to initiate credential issuance, sent by (potential) prover.
128/// Specifies the schema to be used for the credential.
129#[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/// A verifiable credential issued by an issuer upon receiving a `CredentialRequest`.
140/// Specifies the signed values, the DID of the prover/subject, the `CredentialSchema`, and the `CredentialSignature`
141/// including revocation info.
142#[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/// A verifiable credential with a blind signature that still needs to be processed by the holder
196#[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/// A verifiable credential containing a blind signature that still needs to be processed by the holder/receiver.
213#[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/// Payload/data part of a verifiable credential.
251#[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/// 'credentialStatus' property of a verifiable credential containing revocation information.
260#[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/// Payload part of a revocation list credential.
270#[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/// Reference to a credential schema.
279#[derive(Serialize, Deserialize, Clone)]
280#[serde(rename_all = "camelCase")]
281pub struct CredentialSchemaReference {
282    pub id: String,
283    pub r#type: String,
284}
285
286/// The signature ('proof' part) of a BBS+ verifiable credential.
287#[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/// A blinded signature created by an issuer that needs to be finished
300/// by the holder/receiver of this signature.
301#[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/// A collection of all proofs requested in a `ProofRequest`. Sent to a verifier as the response to
314/// a `ProofRequest`.
315#[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/// Proof presentation without a proof (just for internal use)
342#[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/// A verifiable credential exposing requested properties of a `BbsCredential` by providing a Bbs signature proof
353#[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/// A proof object of a `BbsPresentation`
407#[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/// Result of a call to the verifyProof endpoint. Gives the status of a verification (i.e. whether it
420/// was successful or not) and a reason, if rejected.
421#[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/// `RevocationListCredential` without a proof (for internal use only).
431#[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/// A revocation list credential associating verifiable credential revocation IDs to their revocation status as a bit list. See
444/// <https://w3c-ccg.github.io/vc-status-rl-2020/#revocationlist2020credential>
445#[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}