# 7. Proofs

Once a Holder received a verifiable credential he can use it to prove himself to someone else.
Credential verification protocol implemented using Zero-knowledge protocol.
During the credential verification process, the Holder generates digital proof which the Verifier can validate using published Issuer keys which he used during the issuance of the credential, which Holder used to generate the proof.\
Mobile SDK can generate an unlimited number of proof in this way.

There are two roles in the connection establishing process: **Verifier** and **Prover**.
* The Verifier is the party that ask Holder to provide some information about him. [Verity SDK](https://github.com/evernym/verity-sdk) can be used as an **Verifier**.
* The Prover is the party that generates proofs based on the previously sored credentials. **Mobile SDK** represents the **Holder** party. Bellow in this document we will explain which steps need to be taken in order to generate a Proof for received request on the **Prover** side using Mobile SDK.

> **NOTE:** library should be initialized before using proofs API. See [initialization documentation](3.Initialization.md)

> **NOTE:** there must be established connection between Prover and Verifier. See [connections document](5.Connections.md)

> **NOTE:** there must be at least on credential stored in the Holder's wallet. See [credentials document](6.Credentials.md)

To complete this section read through the following sections:

1. [Proof Request Overview](#proof-request-overview)
1. [Responding to Proof Requests](#responding-to-proof-requests)
1. [Proof Request data cases](#proof-request-data-cases)

## Proof Request Overview

Proof Request is a request sent by one of the communication sides to another one in order to get information about it.

There are three types of data that can be requested in a Proof Request:

#### Requested Attributes

Requested Attributes are attributes for which a sender (**Verifier**) wants to know their exact values. \
In other words, the resulting Proof will contain revealed values for requested attributes and math evidence of their correctness.

#### Requested Attribute Groups

Requested Attribute Groups are similar to **Requested Attributes**.
The only difference is that they apply an additional restriction for listed attributes: the same credential **must** be used for their proving.
In other words, the resulting Proof will contain revealed values for each requested attribute and common math evidence (referring to a single credential) of their correctness.

#### Requested Predicates

Requested Predicates are conditions that the sender wants to ensure that receiver has a credential containing attribute which can resolve this condition but **without** revealing an actual value of this attribute. \
In other words, the resulting Proof will contain math evidence of the fact that Prover has a credential resolving condition in the requested predicate, but an exact attribute value will not be revealed.

Predicates can be requested only over fields which has integer representation in a credential (e.x. predicate can be requested for credential field `age` with has value `20` but not `twenty`)

There are 4 types of supported predicates
* `>=` - greater or equal
* `>` - greater
* `<=` - less or equal
* `<` - less

#### Self attested Attributes 

It may happen that User does not have a credential that can be used for filling a requested attribute, but sometimes Verifier may also indicate accepting of attribute values filled by the User.

> Predicates cannot be self-attested. They can be only proved based on the existing credential.

#### Missing Attributes

An attibute is considered as missing if a User does not have a credential that can be used for filling a requested attribute and Verifier didn't allow its self-attesting.
This Proof Request cannot be fulfilled by a User, so he can only reject it. 

> Generating a Proof that will contain only part of requested attributes/predicates will cause an error on the Verifier side (the Proof will not be accepted).

#### Important notes about Proof Request

> SDK function to retrieve credentials for a Proof Request will indicate Self-Attested and Missing attributes.

> **NOTE**: Credentials do not specify units of measurement. 
There is a possible situation when the requested predicate, in theory, is resolvable but no credentials are returned by a library.
Example: credentials contains `height` with value `2` (implies maters) but requested predicate contains `p_value` as `170` (implies centimeters). 
For this case, it will be impossible to fulfill the proof request.

> **NOTE:** Proof may contain only part of credential information (e.g. only one of the multiple credential fields was revealed in the proof. The rest fields are not included in the proof because were not requested).

> **NOTE:** Proof can be built using multiple different credentials (e.g. different credentials were used for filling of requested attributes or predicates).

## Responding to Proof Requests

Aries Present Proof protocol consists of several messages exchange:
* Verifier sends `Presentation Request` message to Prover
* Prover handles `Presentation Request` message and sends `Presentation` message to Verifier

### Steps overview

In order to handle a `Proof Request` a Prover (client) need to take the following steps:

1. Download and Parse Proof Offer Request message received from the Pairwise Cloud Agent.
2. Create Proof state object using parsed Proof Request message\
   2.1. Serialize Proof state object and save serialized representation\
   2.2. Update message (connected to Proof Request) status on the Agent as reviewed
3. Retrieve and select credentials which will be used for Proof Request filling
4. Generate and Share Proof\
   4.1. Deserialize associated Connection state object\
   4.2. Deserialize Proof state object\
   4.3. Generate and Send Proof message\
   4.4. Serialize Proof state object and save serialized representation
5. Reject Proof Request\
   5.1. Deserialize associated Connection state object\
   5.2. Deserialize Proof state object\
   5.3. Send Proof Reject message\
   5.4. Serialize Proof state object and save serialized representation

### 0. Proof Application object

As we mentioned before in the [Storage](./2.Storage.md) document SDK does not save state objects, so the application must care about it.
It is up to the developer regarding what data to store in the application.  
On of the possible formats may match the following structure:
```
{
     "pwDid" - string, // reference to the connection from which proof request was received 
     "serialized" - string, // serialized representation of SDK Proof state object
     "threadId" - string, // Identifier of present ptoof protocol.    
                          // This is needed to match the following messages related to the protocol instance.

     // metadata to show on the UI
     "title": string, // proof request title
     "request_attributes": json // list of attributes requested for proof
     "requested_predicates": json // list of predicates requested for proof

    // optionally
     "connectionName": string // name of the connection from which Crdential Offer was received 
     "connectionLogo": string // logo of the connection from which Crdential Offer was received 
      
     "timestamp": int // optional, time of sharing a proof (it can be shown on the UI)      
     "status" - string, // proof status (pending / shared)
}
```
Later in this document, we will show how to get each of these fields.

### 1. Get Proof Request from pending messages

1. Download pending messages (see [messages documentation](4.MessagesFlow.md) for messages downloading information). Pending messages with `proof request` type should be used.  Extract Proof Request JSON string from the downloaded message (value of `decryptedPayload` field).

   #### Example of Proof Request

    ```json
    {
       "@id":"d7f98364-2995-413d-8d20-ee1c817e1dd2",
       "@type":"did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/present-proof/1.0/request-presentation",
       "comment":"Basic Info",
       "request_presentations~attach":[
          {
             "@id":"libindy-request-presentation-0",
             "data":{
                "base64":"eyJuYW1lIjoicHJvb2ZfZnJvbV9hbGljZSIsIm5vbl9yZXZva2VkIjpudWxsLCJub25jZSI6IjkyNDAzNDI1OTA1OTQ2MzEzNTQwODk2NyIsInJlcXVlc3RlZF9hdHRyaWJ1dGVzIjp7ImF0dHJpYnV0ZV8wIjp7Im5hbWUiOiJNZW1iZXJJRCJ9fSwicmVxdWVzdGVkX3ByZWRpY2F0ZXMiOnt9LCJ2ZXIiOiIxLjAiLCJ2ZXJzaW9uIjoiMS4wIn0="
             },
             "mime-type":"application/json"
          }
       ],
       "~thread": { // (Optional) maybe omitted
          "thid": string,   
       }  
    }
    ```

The following data can be taken from the **Credential Offer** to fill the application Credential object we defined before:
* `~thread.thid` or else `@id` - Identifier of present proof protocol. This value is needed to determine the next protocol message after offer acceptance.

2. Fetch Proof Request attachment content because it contains requested attributes and predicates:
   ### iOS
    ```objc
    [appDelegate.sdkApi extractAttachedMessage: proofRequest
            completion:^(NSError *error, NSString *attachedMessage) {
                // ...
            }];
    ```

   ### Android

    ```java
    int proofHandle = UtilsApi.vcxExtractAttachedMessage(proofRequest).get();
    ```

   #### Example of Proof Request attachment content

    ```json
    {
       "nonce": "220867029780621153091790", // unique nonce 
       "name": "Basic Info",                // name of proof request (can be used on UI instead of `comment` field)
       "version": "0.1",                    // version of Proof Request
       "requested_attributes": {            // requested attributes
           "attribute_1_unique_referent": { // unique identifier of first requested attribute
               "name": "Number",            // name of requested field `Numeber`
               "restrictions": {            // restriction to credentials which can be used for filling of attributes
                  ...
               }
           },
           "attribute_2_unique_referent": { // unique identifier of second requested attribute
               "name": "First Name",        // name of requested field `First Name`
               "restrictions": {            // restriction to credentials which can be used for filling of attributes
                  ...
               }
           }
       },
       "requested_predicates": {            // requested predicates
           "predicate_1_unique_referent": { // unique identifier of first requested predicate
               "name": "Age",               // name of requested field `Age`
               "p_type": ">=",              // type of predicate (supported `>, >=, <, <=`)
               "p_value": 20,                // value of predicate
               "restrictions": {            // restriction to credentials which can be used for filling of attributes
                  ...
               }
           }
       }
    }
    ```

The following data can be taken from the **Credential Offer** to fill the application Credential object we defined before:
* `name` - title of proof request
* `request_attributes` - list of attributes requested for proof
* `requested_predicates` - list of predicates requested for proof

  > In order to fill `pwDid` field you need to take `pairwiseDID` value from the downloaded message.

### 2. Create Proof state object using received Proof Request message

1. Create Credential state object

    ### iOS
    ```objc
    [appDelegate.sdkApi proofCreateWithRequest: sourceId
            withProofRequest: message
            completion:^(NSError *error, vcx_proof_handle_t credentailHandle) {
                // ...
            }];
    ```
    
    ### Android
    
    ```java
    int proofHandle = DisclosedProofApi.proofCreateWithRequest(sourceId, message).get();
    ```
    
    * `sourceId` - random string
    * `message` - message received on step 1

1. Serialize Proof state object

    ### iOS
    ```objc
    [appDelegate.sdkApi proofSerialize: proofHandle
            completion:^(NSError *error, NSString *proof_request) {
                // ...
            }];
    ```
    
    ### Android
    
    ```java
    String serializedProof = DisclosedProofApi.proofSerialize(proofHandle).get();
    ```

1. Save `serialized` sdk credential state object into your application connection object.

1. The `status` of the credential is considered as `pending` at this step.

1. Every time in the future you want to perform some operations using the created Proof object you need firstly to fetch Proof object from the storage and next deserialize SDK object from its serialized representation (receive a new handle).

1. Update status of correspondent message on the Agent as reviewed. See [messages documentation](4.MessagesFlow.md) for message update information.

### 3. Retrieve and select credentials for Proof Request filling

Before responding to a Proof Request you need to select credentials that will be used.

There are two ways of showing a Proof Request to a User:
* Show requested attributes/predicates filling with credential values that will be used. In this case steps, below need to be done before showing a Proof Request.
* Show only requested attributes/predicates without values and automatically select credentials after User accepts. In this case steps, below can be done before showing a Proof Request, as after it is accepted by a User.

1. Deserialize Proof state object associated with Proof Request

    #### iOS
    ```objC
    [appDelegate.sdkApi proofDeserialize:serializedProof
            completion:^(NSError *error, NSInteger proofHandle) {
                // ...
            }];
    ```
    
    #### Android
    ```java
    int proofHandle = ProofApi.proofDeserialize(serializedProof).get();
    ```

1. Retrieve credentials which can be used to fill each requested attribute/predicate in the Proof Request

    ### iOS
    ```objc
    [appDelegate.sdkApi proofDeserialize: serializedProof
            completion:^(NSError *error, vcx_proof_handle_t proofHandle) {
                // ...
                [appDelegate.sdkApi proofRetrieveCredentials: proofHandle
                    withCompletion:^(NSError *error, NSString *retrievedCreds) {
                        // ...                    
                    }];
            }];
    ```
    
    ### Android
    
    ```java
    int proofHandle = DisclosedProofApi.proofDeserialize(serializedProof).get();
    String retrievedCreds = DisclosedProofApi.proofRetrieveCredentials(proofHandle).get();
    ```
    
    Result value will contain JSON object with credentials available for filling of each requested attribute / predicate in the Proof Request:

   #### Result Structure
    ```
    {
         // requested attributes
         "attributes": {
            // unique identifier of requested attribute in the proof request
            "attribute_or_predicate_referent_in_proof_request": {
               // list of credentials which can be used for filling of attribute referenced by `attribute_or_predicate_referent_in_proof_request`
               "credentials": [ 
                  {
                     // credential inforamtion
                     "cred_info":{
                        "attrs":{
                           // all attributes in the credential 
                        },
                        "referent": string, // id of credential in the wallet
                        "cred_def_id": string, // credential definition id
                        "schema_id": string // id of schema
                     },
                     // attributes requested in the proof request with correponding value taken from [cred_info][attrs]
                     "requested_attributes":{
                        "attribute_name": string
                     }
                  }
               ],
               "missing": bool, // indicates if the attribute is missing (there is no credentials and self-attesting disallowed)
               "self_attest_allowed": bool, // indicates if the attribute can be self-attested (any value passed)
               "name": string // attribute name in the proof request
            }   
         },
         // requested predicate
         "predicates": {
            // unique identifier of requested predicate in the proof request
            "predicate_or_predicate_referent_in_proof_request": {
               // list of credentials which can be used for filling of predicate referenced by `predicate_or_predicate_referent_in_proof_request`
               "credentials": [ 
                  {
                     // credential inforamtion
                     "cred_info":{
                        "attrs":{
                           // all attributes in the credential 
                        },
                        "referent": string, // id of credential in the wallet
                        "cred_def_id": string, // credential definition id
                        "schema_id": string // id of schema
                     },
                     // attributes requested in the proof request with correponding value taken from [cred_info][attrs]
                     "requested_attributes":{
                        "attribute_name": string
                     }
                  }
               ],
               "missing": bool, // indicates if the attribute is missing (there is no credentials and self-attesting disallowed)
               "name": string, // attribute name in the proof request
               "p_type": string, // predicate type in the proof request
               "p_value": number // predicate value in the proof request
            } 
         }
    }
   ```

   #### Result Example
    ```
    {
        "attributes": {
            // identifier of first requested attribute in the proof request 
            "attribute_1_unique_referent": {
               // credentials in the wallet which can be used for filling of attribute referenced by `attribute_1_unique_referent`
               "credentials": [ 
                   {
                       // credential information
                       "cred_info": { 
                           "attrs": {
                               "Number": "12345",
                               "First Name": "Alice",
                               "Last Name": "Andersen",
                               "Age": "22"
                           },
                           "referent": "79f68e11-0aaf-4891-8277-1f90f5b05670",
                           "cred_def_id": "R9kuPrDFDVKNRL1oFpRxg2:3:CL:33627:tag1",
                           "schema_id": "R9kuPrDFDVKNRL1oFpRxg2:2:DEMO-Transcript:1.0"
                       },
                       // attributes requested in the proof request with correponding value taken from [cred_info][attrs]
                       "requested_attributes":{
                          "Number": "12345"
                       }
                   }
               ],
               "missing": false, 
               "self_attest_allowed": true,
               "name": "Number",
            },
            // identifier of second requested attribute in the proof request 
            "attribute_2_unique_referent": {
               "credentials": [ 
                   // two credentials which can be used for filling of attribute referenced by `attribute_2_unique_referent`
                   {
                       "cred_info": { // credential information
                           "attrs": {
                               "Number": "12345",
                               "First Name": "Alice",
                               "Last Name": "Andersen",
                               "Age": "22"
                           },
                           "referent": "79f68e11-0aaf-4891-8277-1f90f5b05670",
                           "cred_def_id": "R9kuPrDFDVKNRL1oFpRxg2:3:CL:33627:tag1",
                           "schema_id": "R9kuPrDFDVKNRL1oFpRxg2:2:DEMO-Transcript:1.0"
                       },
                       // attributes requested in the proof request
                       "requested_attributes":{
                          "First Name": "12345"
                       }
                   },
                   {
                       "cred_info": {
                           "attrs": {
                               "number": "433",
                               "firstName": "alice",
                               "lastName": "andersen",
                               "age": "22"
                           },
                           "referent": "de23y421-0aaf-3256-1233-32hk1264934f",
                           "cred_def_id": "C3SFPrDFDVKNRL1oFpRxg2:3:CL:33627:tag1",
                           "schema_id": "R9kuPrDFDVKNRL1oFpRxg2:2:DEMO-Transcript:1.0"
                       },
                       // attributes requested in the proof request
                       "requested_attributes":{
                          "First Name": "alice"
                       }
                   }
               ],
               "missing": false, 
               "self_attest_allowed": true,
               "name": "First Name",
            }
        },
        "predicates": {
            // identifier of first requested predicate in the proof request 
            "predicate_1_unique_referent": {
               "credentials": [ 
                   // only one credential which can be used for filling of predicate referenced by `predicate_1_unique_referent`
                   {
                       "cred_info": { // credential information
                           "attrs": {
                               "Number": "12345",
                               "First Name": "Alice Andersen",
                               "Last Name": "Andersen",
                               "Age": "22"
                           },
                           "cred_def_id": "R9kuPrDFDVKNRL1oFpRxg2:3:CL:33627:tag1",
                           "referent": "79f68e11-0aaf-4891-8277-1f90f5b05670",
                           "schema_id": "R9kuPrDFDVKNRL1oFpRxg2:2:DEMO-Transcript:1.0"
                       },
                       // attributes requested in the proof request
                       "requested_attributes":{
                          "Age": "22"
                       }
                   }
               ],
               "missing": false,
               "name": "Age",
               "p_type": ">=",
               "p_value": 20
            }
        }
    }
    ```

   #### Important Notes

    > There can be several credentials that can be used for filling of requested attribute/predicate. At the next step, you will need to select a single credential for each requested attribute/predicate. 

    > If some attribute/predicate is indicated as `missing` Proof Request can be only rejected.

    > There is no guaranty regarding the order of returned credentials. If you want to select the freshest credential as a default user selection you need to store an additional timestamp to credential id on the application side and sort credentials for requested attributes based on their timestamps.    

1. Select credentials which will be used proving of each requested attribute / predicate.\
   In other words, you need to select a single `credential info` entry for each requested attribute / predicate and build a new object having the following structure:

    ```
    {
        "attrs": {
            // identifier of first requested attribute in the proof request 
            "attribute_1_unique_referent": { 
                "credential": {
                    // credential selected from `retrievedCreds` 
                    "cred_info": { 
                        "attrs": {
                            "Number": "12345",
                            "First Name": "Alice",
                            "Last Name": "Andersen",
                            "Age": "22"
                        },
                        "cred_def_id": "R9kuPrDFDVKNRL1oFpRxg2:3:CL:33627:tag1",
                        "referent": "79f68e11-0aaf-4891-8277-1f90f5b05670",
                        "schema_id": "R9kuPrDFDVKNRL1oFpRxg2:2:DEMO-Transcript:1.0"
                    },
                    "requested_attributes":{
                       "Number": "12345"
                    }
                }
            },
            // identifier of second requested attribute in the proof request 
            "attribute_2_unique_referent": { 
                "credential": {
                    // credential selected from `retrievedCreds` 
                    "cred_info": { 
                        "attrs": {
                            "Number": "12345",
                            "First Name": "Alice",
                            "Last Name": "Andersen",
                            "Age": "22"
                        },
                        "cred_def_id": "R9kuPrDFDVKNRL1oFpRxg2:3:CL:33627:tag1",
                        "referent": "79f68e11-0aaf-4891-8277-1f90f5b05670",
                        "schema_id": "R9kuPrDFDVKNRL1oFpRxg2:2:DEMO-Transcript:1.0"
                    },
                    "requested_attributes":{
                       "First Name": "12345"
                    }
                }
            },
            // identifier of first requested predicate in the proof request 
            "predicate_1_unique_referent": { 
                "credential": {
                    // credential selected from `retrievedCreds` 
                    "cred_info": {
                        "attrs": {
                            "Number": "12345",
                            "First Name": "Alice",
                            "Last Name": "Andersen",
                            "Age": "22"
                        },
                        "cred_def_id": "R9kuPrDFDVKNRL1oFpRxg2:3:CL:33627:tag1",
                        "referent": "79f68e11-0aaf-4891-8277-1f90f5b05670",
                        "schema_id": "R9kuPrDFDVKNRL1oFpRxg2:2:DEMO-Transcript:1.0"
                    },
                    "requested_attributes":{
                       "Age": "22"
                    }
                }
            }
        }
    }
    ```

   Pseudocod for selecting of the first possible credential:

   ```
    selected_credentials = {
        'attrs': {}
    }

    for attribute_referent in retrievedCreds['attributes']:
        selected_credentials['attrs'][attribute_referent] = {
            'credential': retrievedCreds['attributes'][attribute_referent]['credentials'][0]
        }

    for predicate_referent in retrievedCreds['predicates']:
        selected_credentials['attrs'][predicate_referent] = {
            'credential': retrievedCreds['predicates'][predicate_referent]['credentials'][0]
        }
   ```

1. Fill in missing attributes which can be self attested by user (according to Proof Request).

   In this case JSON object with user-provided inputs should be constructed:
   ```
   {
      "attribute_referent_in_proof_request": "Custom value",
      ...
   }
   ```

   > **NOTE:** In case self-attested attributes are not required, empty JSON array should be used: `{}`

1. If user does not have a credential to fill in missing attributes, and these attributes cannot be self attested (according to Proof Request) you will not be able to generate Proof. So you can only reject received Proof Request.

### 4. Share Proof

In case user is able to fulfill received proof request, following steps should be performed to share proof.

1. Deserialize Connection state object associated with received Prof Request message

    #### iOS
    ```objC
    [appDelegate.sdkApi connectionDeserialize:serializedConnection
            completion:^(NSError *error, NSInteger connectionHandle) {
                // ...
            }];
    ```
    
    #### Android
    ```java
    int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
    ```

1. Deserialize Proof state object associated with Proof Request

    #### iOS
    ```objC
    [appDelegate.sdkApi proofDeserialize:serializedProof
            completion:^(NSError *error, NSInteger proofHandle) {
                // ...
            }];
    ```
    
    #### Android
    ```java
    int proofHandle = DisclosedProofApi.proofDeserialize(serializedProof).get();
    ```

1. Generate Proof using selected credentials and self attested attributes

    ### iOS
    ```objc
    [appDelegate.sdkApi proofGenerate: proofHandle
            withSelectedCredentials:selectedCredentials
            withSelfAttestedAttrs:selfAttestedAttributes
            completion:^(NSError *error) {
                // ...
            }];
    ```
    
    ### Android
    
    ```java
    DisclosedProofApi.proofGenerate(proofHandle, selectedCredentials, selfAttestedAttributes).get();
    ```
 
1. Send `Proof` message to Verifier

    ### iOS
    ```objc
    [appDelegate.sdkApi proofSend: proofHandle
            withConnectionHandle:connectionHandle
            completion:^(NSError *error) {
                // ...
            }];
    ```
    
    ### Android
    
    ```java
    DisclosedProofApi.proofSend(proofHandle, connectionHandle).get();
    ```

1. Serialize Proof state object

   #### iOS
    ```objC
    [appDelegate.sdkApi proofSerialize:proofHandle
            completion:^(NSError *error, NSString *state)) {
                // ...
            }];
    ```

   #### Android
    ```java
    String serializedProof = DisclosedProofApi.proofSerialize(proofHandle).get();
    ```

1. The `status` of the proof is considered as `shared` at this step.

1. You also can save the `timestamp` of proof sharing.

1. Update a related record in the storage with the latest value.

### 4. Reject Proof Request

1. Deserialize Connection state object associated with received Prof Request message

    #### iOS
    ```objC
    [appDelegate.sdkApi connectionDeserialize:serializedConnection
            completion:^(NSError *error, NSInteger connectionHandle) {
                // ...
            }];
    ```
    
    #### Android
    ```java
    int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
    ```

1. Deserialize Proof state object associated with Proof Request

    #### iOS
    ```objC
    [appDelegate.sdkApi proofDeserialize:serializedProof
            completion:^(NSError *error, NSInteger proofHandle) {
                // ...
            }];
    ```
    
    #### Android
    ```java
    int proofHandle = DisclosedProofApi.proofDeserialize(serializedProof).get();
    ```

1. Send `Reject Proof Request` message to Verifier

    #### iOS
    ```objc
    [appDelegate.sdkApi proofDeclinePresentationRequest: proofHandle
            withConnectionHandle:connectionHandle
                      withReason:(NSString *)@"Rejection reason"
                    withProposal:(NSString *)nil
            withCompletion:^(NSError *error) {                        
                // ...
            }];
    ```
    
    #### Android
    ```java
    DisclosedProofApi.proofDeclineRequest(proofHandle, connectionHandle, "Rejection reason", null).get();
    ```

1. Serialize Proof state object

   #### iOS
    ```objC
    [appDelegate.sdkApi proofSerialize:proofHandle
            completion:^(NSError *error, NSString *state)) {
                // ...
            }];
    ```

   #### Android
    ```java
    String serializedProof = DisclosedProofApi.proofSerialize(proofHandle).get();
    ```

1. Update a related record in the storage with the latest value of the serialized Proof state object.

## Proof Request data cases

This section shows different formats for Proof Requests that can be sent to credential holder.

1. Request single attribute:
    ```
    "requested_attributes": {
        "attribute_1": {
            "name": "Name"
        },
    }
    ```

1. Request single attribute restricted by Issuer:
    ```
    "requested_attributes": {
        "attribute_1": {
            "name": "Name",
            "restrictions": {"issuer_did": "ANM2cmvMVoWpk6r3pG5FAZ"}
        },
    }
   ```
       
1. Request single attribute restricted by list of Issuer's:
    ```
    "requested_attributes": {
        "attribute_1": {
            "name": "Name",
            "restrictions": {"issuer_did": {"$in": ["ANM2cmvMVoWpk6r3pG5FAZ", "BNM2cmvMVoWpk6r3pG5FAZ"]}}
        },
    }
    ```
   
1. Request single attribute restricted by Credential Definition:
    ```
    "requested_attributes": {
        "attribute_1": {
            "name": "Name",
            "restrictions": {|cred_def_id": "ANM2cmvMVoWpk6r3pG5FAZ:3:CL:1:1"}
        },
    }
    ```

1. Request single attribute that can be self attested:
    ```
    "requested_attributes": {
        "attribute_1": {
            "name": "Name"
        },
    }
    // or 
    "requested_attributes": {
        "attribute_1": {
            "name": "Name",
            "self_attest_allowed": true
        },
    }
    ```

1. Request single attribute that cannot be self attested:
    ```
    "requested_attributes": {
        "attribute_1": {
            "name": "Name"
            "self_attest_allowed": false
        },
    }
    // or set any restriction 
    "requested_attributes": {
        "attribute_1": {
            "name": "Name"
            "restrictions": {"issuer_did": "ANM2cmvMVoWpk6r3pG5FAZ"}
        },
    }
    ```

1. Request couple attributes which can be filled from different credentials:
    ```
    "requested_attributes": {
        "attribute_1": {
            "name": "Name"
        },
        "attribute_2": {
            "name": "Surname"
        },
    }
   ```
    
1. Request couple attributes which must be filled from the same credential:
    ```
    "requested_attributes": {
        "attribute_1": {
            "names": ["Name", "Surname"]
        },
    }
    ```

1. Request couple attributes which must be filled from the same credential and restricted by issuer:
    ```
    "requested_attributes": {
        "attribute_1": {
            "names": ["Name", "Surname"],
            "restrictions": {"issuer_did": "ANM2cmvMVoWpk6r3pG5FAZ"}
        },
    }
    ```

1. Request predicates:
    ```
    // Less or equal
    "requested_predicates": {
        "predicate_1": {
            "name": "Age", "p_type": "<=", "p_value": 30
        },
    }
    // Less
    "requested_predicates": {
        "predicate_1": {
            "name": "Age", "p_type": "<", "p_value": 30
        },
    }
    // Greater
    "requested_predicates": {
        "predicate_1": {
            "name": "Age", "p_type": ">", "p_value": 30
        },
    }
    // Greater or equal
    "requested_predicates": {
        "predicate_1": {
            "name": "Age", "p_type": ">=", "p_value": 30
        },
    }
    ```

1. Request predicates restricted by an issuer:
    ```
       "requested_predicates": {
        "predicate_1": {
            "name": "Age", "p_type": ">=", "p_value": 30,
            "restrictions": {"issuer_did": "ANM2cmvMVoWpk6r3pG5FAZ"}
        },
    }
    ```

## Next Step

Now your application is able to fulfill proof requests using previously received credentials.
You are ready to read how to [reply to secure questions](8.StructuredMessages.md).
