def validate(self): """ Ensure the condition is valid according the local rules. Checks the condition against the local subtypes (supported condition types) and the local maximum fulfillment size. Returns: bool: Whether the condition is valid according to local rules. """ # Get class for type ID, throws on error TypeRegistry.find_by_type_id(self.type_id) # Subtypes can have at most 32 bits with current implementation if len(self.subtypes) > Condition.MAX_SAFE_SUBTYPES: raise ValueError('Subtypes too large to be safely represented') # Assert all requested features are supported by this implementation if any(subtype not in Condition.SUPPORTED_SUBTYPES for subtype in self.subtypes): raise ValueError('Condition requested unsupported feature suites') # Assert the requested fulfillment size # is supported by this implementation if self.cost > Condition.MAX_COST: raise ValueError( 'Condition requested too large of a max fulfillment size') return True
def to_asn1_dict(self): condition_type = TypeRegistry.find_by_type_id(self.type_id) condition_class = condition_type['class'] payload = {'fingerprint': self.hash, 'cost': self.cost} if condition_class.TYPE_CATEGORY == 'compound': subtype_ids = [ TypeRegistry.find_by_name(subtype)['type_id'] for subtype in self.subtypes ] bits = ['0' for bit in range(5)] for subtype_id in subtype_ids: bits[subtype_id] = '1' bitstring = ''.join(bits).rstrip('0') payload['subtypes'] = bitstring return {condition_class.TYPE_ASN1: payload}
def serialize_uri(self): """ Generate the URI form encoding of this condition. Turns the condition into a URI containing only URL-safe characters. This format is convenient for passing around conditions in URLs, JSON and other text-based formats. "cc:" BASE16(TYPE_ID) ":" BASE16(BITMASK) ":" BASE64URL(HASH) ":" BASE10(MAX_COST) Returns: string: Condition as a URI """ condition_type = TypeRegistry.find_by_type_id(self.type_id) condition_class = TypeRegistry.find_by_type_id(self.type_id)['class'] include_subtypes = condition_class.TYPE_CATEGORY == 'compound' uri = 'ni:///sha-256;{}?fpt={}&cost={}'.format( base64_remove_padding( base64.urlsafe_b64encode(self.hash)).decode(), condition_type['name'], self.cost, ) if include_subtypes: uri += '&subtypes=' + ','.join(sorted(self.subtypes)) return uri
def from_asn1_dict(asn1_dict): asn1_type, value = asn1_dict.popitem() registered_type = TypeRegistry.find_by_asn1_type(asn1_type) # Instantiate condition condition = Condition() condition.type_id = registered_type['type_id'] condition.hash = value['fingerprint'] condition.cost = value['cost'] condition._subtypes = set() if registered_type['class'].TYPE_CATEGORY == 'compound': subtypes = { TypeRegistry.find_by_type_id(type_id)['name'] for type_id in compress( range(Condition.MAX_SAFE_SUBTYPES), map(lambda bit: int(bit), value['subtypes']) ) } condition._subtypes.update(subtypes) return condition
def type_name(self): return TypeRegistry.find_by_type_id(self.type_id)['name']