docs: async def create_proof(self, proof_req: dict, briefs: Union[dict, Sequence[dict]], requested_creds: dict) -> str:
          """
          Create proof as HolderProver.
  
          Raise:
              * AbsentLinkSecret if link secret not set
              * CredentialFocus on attempt to create proof on no briefs or multiple briefs for a credential definition
              * AbsentTails if missing required tails file
              * | BadRevStateTime if a timestamp for a revocation registry state in the proof request
                | occurs before revocation registry creation
              * IndyError for any other indy-sdk error
              * AbsentInterval if briefs missing non-revocation interval, but cred def supports revocation
              * WalletState if the wallet is closed.
  
          :param proof_req: proof request as per Verifier.build_proof_req_json()
          :param briefs: cred-brief, sequence thereof, or mapping from wallet cred-id to briefs, to prove
          :param requested_creds: requested credentials data structure; i.e.,
  
          ::
  
              {
                  'self_attested_attributes': {},
                  'requested_attributes': {
                      'attr0_uuid': {
                          'cred_id': string,
                          'timestamp': integer,  # for revocation state
                          'revealed': bool
                      },
                      ...
                  },
                  'requested_predicates': {
                      'predicate0_uuid': {
                          'cred_id': string,
                          'timestamp': integer  # for revocation state
                      }
                  }
              }
  
          :return: proof json
          """
  
          LOGGER.debug(
              'HolderProver.create_proof >>> proof_req: %s, briefs: %s, requested_creds: %s',
              proof_req,
              briefs,
              requested_creds)
  
          if not self.wallet.handle:
              LOGGER.debug('HolderProver.create_proof <!< Wallet %s is closed', self.name)
              raise WalletState('Wallet {} is closed'.format(self.name))
  
          label = await self._assert_link_secret('create_proof')
  
          cd_ids = set()
          x_cd_ids = set()
          for brief in iter_briefs(briefs):
              cd_id = brief['cred_info']['cred_def_id']
              if cd_id in cd_ids and cd_id not in x_cd_ids:
                  x_cd_ids.add(cd_id)
              cd_ids.add(cd_id)
              if x_cd_ids:
                  LOGGER.debug('HolderProver.create_proof <!< briefs specification out of focus (non-uniqueness)')
                  raise CredentialFocus('Briefs list repeats cred defs: {}'.format(x_cd_ids))
  
          s_id2schema = {}  # schema identifier to schema
          cd_id2cred_def = {}  # credential definition identifier to credential definition
          rr_id2timestamp = {}  # revocation registry of interest to timestamp of interest (or None)
          rr_id2cr_id = {}  # revocation registry of interest to credential revocation identifier
          for brief in iter_briefs(briefs):
              interval = brief.get('interval', None)
              cred_info = brief['cred_info']
              s_id = cred_info['schema_id']
              if not ok_schema_id(s_id):
                  LOGGER.debug('HolderProver.create_proof <!< Bad schema id %s', s_id)
                  raise BadIdentifier('Bad schema id {}'.format(s_id))
  
              if s_id not in s_id2schema:
                  schema = json.loads(await self.get_schema(s_id))  # add to cache en passant
                  if not schema:
                      LOGGER.debug(
                          'HolderProver.create_proof <!< absent schema %s, proof req may be for another ledger',
                          s_id)
                      raise AbsentSchema('Absent schema {}, proof req may be for another ledger'.format(s_id))
                  s_id2schema[s_id] = schema
  
              cd_id = cred_info['cred_def_id']
              if not ok_cred_def_id(cd_id):
                  LOGGER.debug('HolderProver.create_proof <!< Bad cred def id %s', cd_id)
                  raise BadIdentifier('Bad cred def id {}'.format(cd_id))
  
              if cd_id not in cd_id2cred_def:
                  cred_def = json.loads(await self.get_cred_def(cd_id))  # add to cache en passant
                  cd_id2cred_def[cd_id] = cred_def
  
              rr_id = cred_info['rev_reg_id']
              if rr_id:
                  if not ok_rev_reg_id(rr_id):
                      LOGGER.debug('HolderProver.create_proof <!< Bad rev reg id %s', rr_id)
                      raise BadIdentifier('Bad rev reg id {}'.format(rr_id))
  
                  await self._sync_revoc_for_proof(rr_id)  # link tails file to its rr_id if it's new
                  if interval:
                      if rr_id not in rr_id2timestamp:
                          if interval['to'] > int(time()):
                              LOGGER.debug(
                                  'HolderProver.create_proof <!< interval to %s for rev reg %s is in the future',
                                  interval['to'],
                                  rr_id)
                              raise BadRevStateTime(
                                  'Revocation registry {} timestamp {} is in the future'.format(rr_id, interval['to']))
                          rr_id2timestamp[rr_id] = interval['to']
                  elif 'revocation' in cd_id2cred_def[cd_id]['value']:
                      LOGGER.debug(
                          'HolderProver.create_proof <!< brief on cred def id %s missing non-revocation interval',
                          cd_id)
                      raise AbsentInterval('Brief on cred def id {} missing non-revocation interval'.format(cd_id))
                  if rr_id in rr_id2cr_id:
                      continue
                  rr_id2cr_id[rr_id] = cred_info['cred_rev_id']
  
          rr_id2rev_state = {}  # revocation registry identifier to its state
          with REVO_CACHE.lock:
              for rr_id in rr_id2timestamp:
                  revo_cache_entry = REVO_CACHE.get(rr_id, None)
                  tails = revo_cache_entry.tails if revo_cache_entry else None
                  if tails is None:  # missing tails file
                      LOGGER.debug('HolderProver.create_proof <!< missing tails file for rev reg id %s', rr_id)
                      raise AbsentTails('Missing tails file for rev reg id {}'.format(rr_id))
                  rr_def_json = await self.get_rev_reg_def(rr_id)
                  (rr_delta_json, ledger_timestamp) = await revo_cache_entry.get_delta_json(
                      self._build_rr_delta_json,
                      rr_id2timestamp[rr_id],
                      rr_id2timestamp[rr_id])
                  rr_state_json = await anoncreds.create_revocation_state(
                      tails.reader_handle,
                      rr_def_json,
                      rr_delta_json,
                      ledger_timestamp,
                      rr_id2cr_id[rr_id])
                  rr_id2rev_state[rr_id] = {
                      rr_id2timestamp[rr_id]: json.loads(rr_state_json)
                  }
  
          rv = await anoncreds.prover_create_proof(
              self.wallet.handle,
              json.dumps(proof_req),
              json.dumps(requested_creds),
              label,
              json.dumps(s_id2schema),
              json.dumps(cd_id2cred_def),
              json.dumps(rr_id2rev_state))
          LOGGER.debug('HolderProver.create_proof <<< %s', rv)
          return rv