def proof_req_pred_referents(proof_req: dict) -> dict: """ Given a proof request with all requested predicates having cred def id restrictions, return its predicate referents by cred def id and attribute, mapping a predicate and a limit. The returned structure can be useful in downstream processing to filter cred-infos for predicates. :param proof_req: proof request with all requested predicate specifications having cred def id restriction; e.g., :: { 'name': 'proof_req', 'version': '0.0', 'requested_attributes': { ... } 'requested_predicates': { '194_highscore_GE_uuid': { 'name': 'highscore', 'p_type': '>=', 'p_value': '100000', 'restrictions': { 'cred_def_id': 'WgWxqztrNooG92RXvxSTWv:3:CL:194:tag' }, 'non_revoked': { ... } }, '194_level_GE_uuid': { 'name': 'level', 'p_type': '>=', 'p_value': '10', 'restrictions': { 'cred_def_id': 'WgWxqztrNooG92RXvxSTWv:3:CL:194:tag' }, 'non_revoked': { ... } }, '194_attempts_LE_uuid': { 'name': 'attempts', 'p_type': '<=', 'p_value': '3', 'restrictions': { 'cred_def_id': 'WgWxqztrNooG92RXvxSTWv:3:CL:194:tag' }, 'non_revoked': { ... } }, '198_employees_LT_uuid': { 'name': 'employees', 'p_type': '<', 'p_value': '100', 'restrictions': { 'cred_def_id': 'WgWxqztrNooG92RXvxSTWv:3:CL:198:tag' }, 'non_revoked': { ... } }, '198_employees_GE_uuid': { 'name': 'employees', 'p_type': '>=', 'p_value': '50', 'restrictions': { 'cred_def_id': 'WgWxqztrNooG92RXvxSTWv:3:CL:198:tag' }, 'non_revoked': { ... } }, } } :return: nested dict mapping cred def id to name to proof request referent to predicate and limit; e.g., :: { 'WgWxqztrNooG92RXvxSTWv:3:CL:194:tag': { 'highscore': { '194_level_GE_uuid': ['>=', 100000] }, 'level': { '194_level_GE_uuid': ['>=', 10] }, 'attempts': { '194_attempts_LE_uuid': ['<=', 3] } }, 'WgWxqztrNooG92RXvxSTWv:3:CL:198:tag': { 'employees': { # may have many preds per attr, but always 1 uuid and 1 relation per pred '198_LT_employees_uuid': ['<=', 100] '198_GE_employees_uuid': ['>=', 50] } } } """ rv = {} for uuid, spec in proof_req['requested_predicates'].items(): cd_id = None for restriction in spec.get('restrictions', []): cd_id = restriction.get('cred_def_id', None) if cd_id: break if not cd_id: continue if cd_id not in rv: # cd_id of None is not OK rv[cd_id] = {} if spec['name'] not in rv[cd_id]: rv[cd_id][spec['name']] = {} rv[cd_id][spec['name']][uuid] = [spec['p_type'], Predicate.to_int(spec['p_value'])] return rv
async def build_proof_req_json(self, cd_id2spec: dict) -> str: """ Build and return indy-sdk proof request for input attributes and non-revocation intervals by cred def id. :param cd_id2spec: dict mapping cred def ids to: - (optionally) 'attrs': lists of names of attributes of interest (omit for all, empty list or None for none) - (optionally) '>=': (pred) inclusive int lower-bounds of interest (omit, empty list, or None for none) - (optionally) '>': (pred) exclusive int lower-bounds of interest (omit, empty list, or None for none) - (optionally) '<=': (pred) inclusive int upper-bounds of interest (omit, empty list, or None for none) - (optionally) '<': (pred) exclusive int upper-bounds of interest (omit, empty list, or None for none) - (optionally), 'interval': either - (2-tuple) pair of epoch second counts marking 'from' and 'to' timestamps, or - | single epoch second count to set 'from' and 'to' the same; default | (now, now) for cred defs supporting revocation or None otherwise; e.g., :: { 'Vx4E82R17q...:3:CL:16:tag': { 'attrs': [ # request attrs 'name' and 'favouriteDrink' from this cred def's schema 'name', 'favouriteDrink' ], '>=': { # request predicate score>=80 from this cred def 'score': 80 } '<=': { # request ranking <=10 from this cred def 'ranking': 10 } 'interval': 1528116008 # same instant for all attrs and preds of corresponding schema }, 'R17v42T4pk...:3:CL:19:tag': None, # request all attrs, no preds, default intervals on all attrs 'e3vc5K168n...:3:CL:23:tag': {}, # request all attrs, no preds, default intervals on all attrs 'Z9ccax812j...:3:CL:27:tag': { # request all attrs, no preds, this interval on all attrs 'interval': (1528112408, 1528116008) }, '9cHbp54C8n...:3:CL:37:tag': { # request no attrs and some predicates; specify interval 'attrs': [], # or equivalently, 'attrs': None '>=': { 'employees': '50' # nicety: implementation converts to int for caller }, '>=': { 'revenue': '10000000' # nicety: implementation converts to int for caller 'ebidta': 0 } 'interval': (1528029608, 1528116008) }, '6caBcmLi33...:3:CL:41:tag': { # all attrs, one pred, default intervals to now on attrs & pred '>': { 'regEpoch': 1514782800 } }, ... } :return: indy-sdk proof request json """ LOGGER.debug('Verifier.build_proof_req_json >>> cd_id2spec: %s', cd_id2spec) cd_id2schema = {} now = int(time()) rv = { 'nonce': str(int(time())), 'name': 'proof_req', 'version': '0.0', 'requested_attributes': {}, 'requested_predicates': {} } for cd_id in cd_id2spec: if not ok_cred_def_id(cd_id): LOGGER.debug( 'Verifier.build_proof_req_json <!< Bad cred def id %s', cd_id) raise BadIdentifier('Bad cred def id {}'.format(cd_id)) interval = None cred_def = json.loads(await self.get_cred_def(cd_id)) seq_no = cred_def_id2seq_no(cd_id) cd_id2schema[cd_id] = json.loads(await self.get_schema(seq_no)) if 'revocation' in cred_def['value']: fro_to = cd_id2spec[cd_id].get( 'interval', (now, now)) if cd_id2spec[cd_id] else (now, now) interval = { 'from': fro_to if isinstance(fro_to, int) else min(fro_to), 'to': fro_to if isinstance(fro_to, int) else max(fro_to) } for attr in (cd_id2spec[cd_id].get( 'attrs', cd_id2schema[cd_id]['attrNames']) or [] if cd_id2spec[cd_id] else cd_id2schema[cd_id]['attrNames']): attr_uuid = '{}_{}_uuid'.format(seq_no, canon(attr)) rv['requested_attributes'][attr_uuid] = { 'name': attr, 'restrictions': [{ 'cred_def_id': cd_id }] } if interval: rv['requested_attributes'][attr_uuid][ 'non_revoked'] = interval for pred in Predicate: for attr in (cd_id2spec[cd_id].get(pred.value.math, {}) or {} if cd_id2spec[cd_id] else {}): pred_uuid = '{}_{}_{}_uuid'.format(seq_no, canon(attr), pred.value.fortran) try: rv['requested_predicates'][pred_uuid] = { 'name': attr, 'p_type': pred.value.math, 'p_value': Predicate.to_int( cd_id2spec[cd_id][pred.value.math][attr]), 'restrictions': [{ 'cred_def_id': cd_id }] } except ValueError: LOGGER.info( 'cannot build %s predicate on non-int bound %s for %s', pred.value.fortran, cd_id2spec[cd_id][pred.value.math][attr], attr) continue # int conversion failed - reject candidate if interval: rv['requested_predicates'][pred_uuid][ 'non_revoked'] = interval LOGGER.debug('Verifier.build_proof_req_json <<< %s', json.dumps(rv)) return json.dumps(rv)