Creates a proof according to the given proof request
    Either a corresponding credential with optionally revealed attributes or self-attested attribute must be provided
    for each requested attribute (see indy_prover_get_credentials_for_pool_req).
    A proof request may request multiple credentials from different schemas and different issuers.
    All required schemas, public keys and revocation registries must be provided.
    The proof request also contains nonce.
    The proof contains either proof or self-attested attribute value for each requested attribute.

    :param wallet_handle: wallet handler (created by open_wallet).
    :param proof_req_json: proof request json
        {
            "name": string,
            "version": string,
            "nonce": string,
            "requested_attributes": { // set of requested attributes
                 "<attr_referent>": <attr_info>, // see below
                 ...,
            },
            "requested_predicates": { // set of requested predicates
                 "<predicate_referent>": <predicate_info>, // see below
                 ...,
             },
            "non_revoked": Optional<<non_revoc_interval>>, // see below,
                           // If specified prover must proof non-revocation
                           // for date in this interval for each attribute
                           // (can be overridden on attribute level)
        }
    :param requested_credentials_json: either a credential or self-attested attribute for each requested attribute
        {
            "self_attested_attributes": {
                "self_attested_attribute_referent": string
            },
            "requested_attributes": {
                "requested_attribute_referent_1": {"cred_id": string, "timestamp": Optional<number>, revealed: <bool> }},
                "requested_attribute_referent_2": {"cred_id": string, "timestamp": Optional<number>, revealed: <bool> }}
            },
            "requested_predicates": {
                "requested_predicates_referent_1": {"cred_id": string, "timestamp": Optional<number> }},
            }
        }
    :param master_secret_name: the id of the master secret stored in the wallet
    :param schemas_json: all schemas json participating in the proof request
          {
              <schema1_id>: <schema1_json>,
              <schema2_id>: <schema2_json>,
              <schema3_id>: <schema3_json>,
          }
    :param credential_defs_json: all credential definitions json participating in the proof request
          {
              "cred_def1_id": <credential_def1_json>,
              "cred_def2_id": <credential_def2_json>,
              "cred_def3_id": <credential_def3_json>,
          }
    :param rev_states_json: all revocation states json participating in the proof request
          {
              "rev_reg_def1_id": {
                  "timestamp1": <rev_state1>,
                  "timestamp2": <rev_state2>,
              },
              "rev_reg_def2_id": {
                  "timestamp3": <rev_state3>
              },
              "rev_reg_def3_id": {
                  "timestamp4": <rev_state4>
              },
          }
    where
     wql query: indy-sdk/docs/design/011-wallet-query-language/README.md
     attr_referent: Proof-request local identifier of requested attribute
     attr_info: Describes requested attribute
         {
             "name": string, // attribute name, (case insensitive and ignore spaces)
             "restrictions": Optional<[<wql query>]>,
                              // if specified, credential must satisfy to one of the given restriction.
             "non_revoked": Optional<<non_revoc_interval>>, // see below,
                            // If specified prover must proof non-revocation
                            // for date in this interval this attribute
                            // (overrides proof level interval)
         }
     predicate_referent: Proof-request local identifier of requested attribute predicate
     predicate_info: Describes requested attribute predicate
         {
             "name": attribute name, (case insensitive and ignore spaces)
             "p_type": predicate type (Currently >= only)
             "p_value": predicate value
             "restrictions": Optional<[<wql query>]>,
                             // if specified, credential must satisfy to one of the given restriction.
             "non_revoked": Optional<<non_revoc_interval>>, // see below,
                            // If specified prover must proof non-revocation
                            // for date in this interval this attribute
                            // (overrides proof level interval)
         }
     non_revoc_interval: Defines non-revocation interval
         {
             "from": Optional<int>, // timestamp of interval beginning
             "to": Optional<int>, // timestamp of interval ending
         }

    :return: Proof json
      For each requested attribute either a proof (with optionally revealed attribute value) or
      self-attested attribute value is provided.
      Each proof is associated with a credential and corresponding schema_id, cred_def_id, rev_reg_id and timestamp.
      There is also aggregated proof part common for all credential proofs.
          {
              "requested_proof": {
                  "revealed_attrs": {
                      "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string},
                      "requested_attr4_id": {sub_proof_index: number: string, encoded: string},
                  },
                  "unrevealed_attrs": {
                      "requested_attr3_id": {sub_proof_index: number}
                  },
                  "self_attested_attrs": {
                      "requested_attr2_id": self_attested_value,
                  },
                  "requested_predicates": {
                      "requested_predicate_1_referent": {sub_proof_index: int},
                      "requested_predicate_2_referent": {sub_proof_index: int},
                  }
              }
              "proof": {
                  "proofs": [ <credential_proof>, <credential_proof>, <credential_proof> ],
                  "aggregated_proof": <aggregated_proof>
              }
              "identifiers": [{schema_id, cred_def_id, Optional<rev_reg_id>, Optional<timestamp>}]
          }

async def prover_create_proof(wallet_handle: int,
                              proof_req_json: str,
                              requested_credentials_json: str,
                              master_secret_name: str,
                              schemas_json: str,
                              credential_defs_json: str,
                              rev_states_json: str) -> str:
    """
    Creates a proof according to the given proof request
    Either a corresponding credential with optionally revealed attributes or self-attested attribute must be provided
    for each requested attribute (see indy_prover_get_credentials_for_pool_req).
    A proof request may request multiple credentials from different schemas and different issuers.
    All required schemas, public keys and revocation registries must be provided.
    The proof request also contains nonce.
    The proof contains either proof or self-attested attribute value for each requested attribute.

    :param wallet_handle: wallet handler (created by open_wallet).
    :param proof_req_json: proof request json
        {
            "name": string,
            "version": string,
            "nonce": string,
            "requested_attributes": { // set of requested attributes
                 "<attr_referent>": <attr_info>, // see below
                 ...,
            },
            "requested_predicates": { // set of requested predicates
                 "<predicate_referent>": <predicate_info>, // see below
                 ...,
             },
            "non_revoked": Optional<<non_revoc_interval>>, // see below,
                           // If specified prover must proof non-revocation
                           // for date in this interval for each attribute
                           // (can be overridden on attribute level)
        }
    :param requested_credentials_json: either a credential or self-attested attribute for each requested attribute
        {
            "self_attested_attributes": {
                "self_attested_attribute_referent": string
            },
            "requested_attributes": {
                "requested_attribute_referent_1": {"cred_id": string, "timestamp": Optional<number>, revealed: <bool> }},
                "requested_attribute_referent_2": {"cred_id": string, "timestamp": Optional<number>, revealed: <bool> }}
            },
            "requested_predicates": {
                "requested_predicates_referent_1": {"cred_id": string, "timestamp": Optional<number> }},
            }
        }
    :param master_secret_name: the id of the master secret stored in the wallet
    :param schemas_json: all schemas json participating in the proof request
          {
              <schema1_id>: <schema1_json>,
              <schema2_id>: <schema2_json>,
              <schema3_id>: <schema3_json>,
          }
    :param credential_defs_json: all credential definitions json participating in the proof request
          {
              "cred_def1_id": <credential_def1_json>,
              "cred_def2_id": <credential_def2_json>,
              "cred_def3_id": <credential_def3_json>,
          }
    :param rev_states_json: all revocation states json participating in the proof request
          {
              "rev_reg_def1_id": {
                  "timestamp1": <rev_state1>,
                  "timestamp2": <rev_state2>,
              },
              "rev_reg_def2_id": {
                  "timestamp3": <rev_state3>
              },
              "rev_reg_def3_id": {
                  "timestamp4": <rev_state4>
              },
          }
    where
     wql query: indy-sdk/docs/design/011-wallet-query-language/README.md
     attr_referent: Proof-request local identifier of requested attribute
     attr_info: Describes requested attribute
         {
             "name": string, // attribute name, (case insensitive and ignore spaces)
             "restrictions": Optional<[<wql query>]>,
                              // if specified, credential must satisfy to one of the given restriction.
             "non_revoked": Optional<<non_revoc_interval>>, // see below,
                            // If specified prover must proof non-revocation
                            // for date in this interval this attribute
                            // (overrides proof level interval)
         }
     predicate_referent: Proof-request local identifier of requested attribute predicate
     predicate_info: Describes requested attribute predicate
         {
             "name": attribute name, (case insensitive and ignore spaces)
             "p_type": predicate type (Currently >= only)
             "p_value": predicate value
             "restrictions": Optional<[<wql query>]>,
                             // if specified, credential must satisfy to one of the given restriction.
             "non_revoked": Optional<<non_revoc_interval>>, // see below,
                            // If specified prover must proof non-revocation
                            // for date in this interval this attribute
                            // (overrides proof level interval)
         }
     non_revoc_interval: Defines non-revocation interval
         {
             "from": Optional<int>, // timestamp of interval beginning
             "to": Optional<int>, // timestamp of interval ending
         }

    :return: Proof json
      For each requested attribute either a proof (with optionally revealed attribute value) or
      self-attested attribute value is provided.
      Each proof is associated with a credential and corresponding schema_id, cred_def_id, rev_reg_id and timestamp.
      There is also aggregated proof part common for all credential proofs.
          {
              "requested_proof": {
                  "revealed_attrs": {
                      "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string},
                      "requested_attr4_id": {sub_proof_index: number: string, encoded: string},
                  },
                  "unrevealed_attrs": {
                      "requested_attr3_id": {sub_proof_index: number}
                  },
                  "self_attested_attrs": {
                      "requested_attr2_id": self_attested_value,
                  },
                  "requested_predicates": {
                      "requested_predicate_1_referent": {sub_proof_index: int},
                      "requested_predicate_2_referent": {sub_proof_index: int},
                  }
              }
              "proof": {
                  "proofs": [ <credential_proof>, <credential_proof>, <credential_proof> ],
                  "aggregated_proof": <aggregated_proof>
              }
              "identifiers": [{schema_id, cred_def_id, Optional<rev_reg_id>, Optional<timestamp>}]
          }
    """

    logger = logging.getLogger(__name__)
    logger.debug("prover_create_proof: >>> wallet_handle: %r, proof_req_json: %r, requested_credentials_json: %r, "
                 "schemas_json: %r, master_secret_name: %r, credential_defs_json: %r, rev_infos_json: %r",
                 wallet_handle,
                 proof_req_json,
                 requested_credentials_json,
                 schemas_json,
                 master_secret_name,
                 credential_defs_json,
                 rev_states_json)

    if not hasattr(prover_create_proof, "cb"):
        logger.debug("prover_create_proof: Creating callback")
        prover_create_proof.cb = create_cb(CFUNCTYPE(None, c_int32, c_int32, c_char_p))

    c_wallet_handle = c_int32(wallet_handle)
    c_proof_req_json = c_char_p(proof_req_json.encode('utf-8'))
    c_requested_credentials_json = c_char_p(requested_credentials_json.encode('utf-8'))
    c_schemas_json = c_char_p(schemas_json.encode('utf-8'))
    c_master_secret_name = c_char_p(master_secret_name.encode('utf-8'))
    c_credential_defs_json = c_char_p(credential_defs_json.encode('utf-8'))
    c_rev_infos_json = c_char_p(rev_states_json.encode('utf-8'))

    proof_json = await do_call('indy_prover_create_proof',
                               c_wallet_handle,
                               c_proof_req_json,
                               c_requested_credentials_json,
                               c_master_secret_name,
                               c_schemas_json,
                               c_credential_defs_json,
                               c_rev_infos_json,
                               prover_create_proof.cb)

    res = proof_json.decode()
    logger.debug("prover_create_proof: <<< res: %r", res)
    return res