def from_dict(cls, data): """Transforms a Python dictionary to an Input object. Note: Optionally, this method can also serialize a Cryptoconditions- Fulfillment that is not yet signed. Args: data (dict): The Input to be transformed. Returns: :class:`~bigchaindb.common.transaction.Input` Raises: InvalidSignature: If an Input's URI couldn't be parsed. """ try: fulfillment = Fulfillment.from_uri(data['fulfillment']) except ValueError: # TODO FOR CC: Throw an `InvalidSignature` error in this case. raise InvalidSignature("Fulfillment URI couldn't been parsed") except TypeError: # NOTE: See comment about this special case in # `Input.to_dict` fulfillment = Fulfillment.from_dict(data['fulfillment']) fulfills = TransactionLink.from_dict(data['fulfills']) return cls(fulfillment, data['owners_before'], fulfills)
def from_dict(cls, data): """Transforms a Python dictionary to an Input object. Note: Optionally, this method can also serialize a Cryptoconditions- Fulfillment that is not yet signed. Args: data (dict): The Input to be transformed. Returns: :class:`~bigchaindb.common.transaction.Input` Raises: InvalidSignature: If an Input's URI couldn't be parsed. """ fulfillment = data['fulfillment'] if not isinstance(fulfillment, Fulfillment): try: fulfillment = Fulfillment.from_uri(data['fulfillment']) except ASN1DecodeError: # TODO Remove as it is legacy code, and simply fall back on # ASN1DecodeError raise InvalidSignature("Fulfillment URI couldn't been parsed") except TypeError: # NOTE: See comment about this special case in # `Input.to_dict` fulfillment = Fulfillment.from_dict(data['fulfillment']) fulfills = TransactionLink.from_dict(data['fulfills']) return cls(fulfillment, data['owners_before'], fulfills)
def test_serialize_condition_and_validate_fulfillment( self, fulfillment_sha256, fulfillment_ed25519, fulfillment_threshold): ilp_fulfillment_ed25519 = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) ilp_fulfillment_sha = Fulfillment.from_uri( fulfillment_sha256['fulfillment_uri']) assert ilp_fulfillment_ed25519.validate(MESSAGE) == True assert ilp_fulfillment_sha.validate(MESSAGE) == True threshold = 1 # Create a threshold condition fulfillment = ThresholdSha256Fulfillment(threshold=threshold) fulfillment.add_subfulfillment(ilp_fulfillment_ed25519) fulfillment.add_subfulfillment(ilp_fulfillment_sha) assert fulfillment.condition.serialize_uri( ) == fulfillment_threshold['condition_uri'] # Note: If there are more than enough fulfilled subconditions, shorter # fulfillments will be chosen over longer ones. # thresholdFulfillmentUri.length === 65 assert fulfillment.serialize_uri( ) == fulfillment_threshold['fulfillment_uri'] assert fulfillment.validate(MESSAGE)
def test_serialize_deserialize_fulfillment(self, fulfillment_ed25519): ilp_fulfillment = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) num_fulfillments = 20 threshold = ceil(num_fulfillments * 2 / 3) # Create a threshold condition fulfillment = ThresholdSha256Fulfillment(threshold=threshold) for i in range(num_fulfillments): fulfillment.add_subfulfillment(ilp_fulfillment) fulfillment_uri = fulfillment.serialize_uri() assert fulfillment.validate(MESSAGE) deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri) assert isinstance(deserialized_fulfillment, ThresholdSha256Fulfillment) assert deserialized_fulfillment.threshold == threshold assert len([ f for f in deserialized_fulfillment.subconditions if f['type'] == 'fulfillment' ]) == threshold assert len(deserialized_fulfillment.subconditions) == num_fulfillments assert deserialized_fulfillment.serialize_uri() == fulfillment_uri assert deserialized_fulfillment.validate(MESSAGE)
def test_from_binary_with_invalid_value(self, fulfillment, error): from cryptoconditions import Fulfillment from cryptoconditions.exceptions import ASN1DecodeError with pytest.raises(ASN1DecodeError) as exc: Fulfillment.from_binary(fulfillment) assert exc.value.args == ('Failed to decode fulfillment.',) assert isinstance(exc.value.__cause__, error)
def test_escrow_abort(self, fulfillment_sha256, fulfillment_ed25519): ilp_fulfillment_sha = Fulfillment.from_uri( fulfillment_sha256['fulfillment_uri']) ilp_fulfillment_ed = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) time_sleep = 0 fulfillment_escrow = ThresholdSha256Fulfillment(threshold=1) fulfillment_timeout = TimeoutFulfillment( expire_time=str(float(timestamp()) + time_sleep)) fulfillment_timeout_inverted = InvertedThresholdSha256Fulfillment( threshold=1) fulfillment_timeout_inverted.add_subfulfillment(fulfillment_timeout) # do not fulfill execute branch fulfillment_and_execute = ThresholdSha256Fulfillment(threshold=2) fulfillment_and_execute.add_subcondition(ilp_fulfillment_ed.condition) fulfillment_and_execute.add_subfulfillment(fulfillment_timeout) fulfillment_and_abort = ThresholdSha256Fulfillment(threshold=2) fulfillment_and_abort.add_subfulfillment(ilp_fulfillment_sha) fulfillment_and_abort.add_subfulfillment(fulfillment_timeout_inverted) fulfillment_escrow.add_subfulfillment(fulfillment_and_execute) fulfillment_escrow.add_subfulfillment(fulfillment_and_abort) # out-of-time validation assert fulfillment_escrow.validate(MESSAGE, now=timestamp()) is True
def test_fulfillment_didnt_reach_threshold(self, vk_ilp, fulfillment_ed25519): ilp_fulfillment = Fulfillment.from_uri(fulfillment_ed25519['fulfillment_uri']) threshold = 10 # Create a threshold condition fulfillment = ThresholdSha256(threshold=threshold) for i in range(threshold - 1): fulfillment.add_subfulfillment(ilp_fulfillment) with pytest.raises(KeyError): fulfillment.serialize_uri() assert fulfillment.validate(MESSAGE) is False fulfillment.add_subfulfillment(ilp_fulfillment) fulfillment_uri = fulfillment.serialize_uri() assert fulfillment.validate(MESSAGE) deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri) assert isinstance(deserialized_fulfillment, ThresholdSha256) assert deserialized_fulfillment.threshold == threshold assert len([f for f in deserialized_fulfillment.subconditions if f['type'] == 'fulfillment']) == threshold assert len(deserialized_fulfillment.subconditions) == threshold assert deserialized_fulfillment.serialize_uri() == fulfillment_uri assert deserialized_fulfillment.validate(MESSAGE) fulfillment.add_subfulfillment(Ed25519Sha256(public_key=VerifyingKey(vk_ilp['b58']))) assert fulfillment.validate(MESSAGE) == True
def from_dict(cls, ffill): """Transforms a Python dictionary to a Fulfillment object. Note: Optionally, this method can also serialize a Cryptoconditions- Fulfillment that is not yet signed. Args: ffill (dict): The Fulfillment to be transformed. Returns: :class:`~bigchaindb.common.transaction.Fulfillment` Raises: InvalidSignature: If a Fulfillment's URI couldn't be parsed. """ try: fulfillment = CCFulfillment.from_uri(ffill['fulfillment']) except ValueError: # TODO FOR CC: Throw an `InvalidSignature` error in this case. raise InvalidSignature("Fulfillment URI couldn't been parsed") except TypeError: # NOTE: See comment about this special case in # `Fulfillment.to_dict` fulfillment = CCFulfillment.from_dict(ffill['fulfillment']) input_ = TransactionLink.from_dict(ffill['input']) return cls(fulfillment, ffill['owners_before'], input_)
def test_from_binary_with_invalid_value(self, fulfillment, error): from cryptoconditions import Fulfillment from cryptoconditions.exceptions import ASN1DecodeError with pytest.raises(ASN1DecodeError) as exc: Fulfillment.from_binary(fulfillment) assert exc.value.args == ('Failed to decode fulfillment.', ) assert isinstance(exc.value.__cause__, error)
def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): from bigchaindb.common.transaction import Input from cryptoconditions import Fulfillment expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) ffill = { 'owners_before': [user_pub], 'fulfillment': Fulfillment.from_uri(ffill_uri), 'fulfills': None, } input = Input.from_dict(ffill) assert input == expected
def test_fulfillment_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub): from bigchaindb_common.transaction import Fulfillment from cryptoconditions import Fulfillment as CCFulfillment expected = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub]) ffill = { 'owners_before': [user_pub], 'fulfillment': CCFulfillment.from_uri(ffill_uri), 'input': None, } ffill = Fulfillment.from_dict(ffill) assert ffill == expected
def test_deserialize_signed_dict_to_fulfillment(self, fulfillment_ed25519): fulfillment = Fulfillment.from_uri(fulfillment_ed25519['fulfillment_uri']) parsed_fulfillment = fulfillment.from_dict(fulfillment.to_dict()) assert parsed_fulfillment.serialize_uri() == fulfillment_ed25519['fulfillment_uri'] assert parsed_fulfillment.condition.serialize_uri() == fulfillment.condition.serialize_uri() assert parsed_fulfillment.to_dict() == fulfillment.to_dict()
def test_fulfillment_serialize_to_dict(self, fulfillment_sha256): fulfillment = Fulfillment.from_uri(fulfillment_sha256['fulfillment_uri']) parsed_fulfillment = fulfillment.from_dict(fulfillment.to_dict()) assert parsed_fulfillment.serialize_uri() == fulfillment.serialize_uri() assert parsed_fulfillment.condition.serialize_uri() == fulfillment.condition.serialize_uri() assert parsed_fulfillment.to_dict() == fulfillment.to_dict()
def from_dict(cls, data): """Transforms a Python dictionary to an Input object. Note: Optionally, this method can also serialize a Cryptoconditions- Fulfillment that is not yet signed. Args: data (dict): The Input to be transformed. Returns: :class:`~bigchaindb.common.transaction.Input` Raises: InvalidSignature: If an Input's URI couldn't be parsed. """ fulfillment = data['fulfillment'] if not isinstance(fulfillment, Fulfillment): try: fulfillment = Fulfillment.from_uri(data['fulfillment']) except ASN1DecodeError: # TODO Remove as it is legacy code, and simply fall back on # ASN1DecodeError raise InvalidSignature("Fulfillment URI couldn't been parsed") except TypeError: # NOTE: See comment about this special case in # `Input.to_dict` fulfillment = _fulfillment_from_details(data['fulfillment']) fulfills = TransactionLink.from_dict(data['fulfills']) return cls(fulfillment, data['owners_before'], fulfills)
def test_weights(self, fulfillment_ed25519): ilp_fulfillment = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) fulfillment1 = ThresholdSha256Fulfillment(threshold=2) fulfillment1.add_subfulfillment(ilp_fulfillment, weight=2) parsed_fulfillment1 = fulfillment1.from_dict(fulfillment1.to_dict()) assert parsed_fulfillment1.condition.serialize_uri( ) == fulfillment1.condition.serialize_uri() assert parsed_fulfillment1.to_dict() == fulfillment1.to_dict() assert parsed_fulfillment1.subconditions[0]['weight'] == 2 assert parsed_fulfillment1.validate(MESSAGE) is True fulfillment2 = ThresholdSha256Fulfillment(threshold=3) fulfillment2.add_subfulfillment(ilp_fulfillment, weight=2) parsed_fulfillment2 = fulfillment1.from_dict(fulfillment2.to_dict()) assert parsed_fulfillment2.subconditions[0]['weight'] == 2 assert parsed_fulfillment2.validate(MESSAGE) is False fulfillment3 = ThresholdSha256Fulfillment(threshold=3) fulfillment3.add_subfulfillment(ilp_fulfillment, weight=3) parsed_fulfillment3 = fulfillment1.from_dict(fulfillment3.to_dict()) assert parsed_fulfillment3.condition.serialize_uri( ) == fulfillment3.condition.serialize_uri() assert not (fulfillment3.condition.serialize_uri() == fulfillment1.condition.serialize_uri()) assert parsed_fulfillment3.validate(MESSAGE) is True fulfillment4 = ThresholdSha256Fulfillment(threshold=2) with pytest.raises(ValueError): fulfillment4.add_subfulfillment(ilp_fulfillment, weight=-2)
def from_dict(cls, data): """Transforms a Python dictionary to an Output object. Note: To pass a serialization cycle multiple times, a Cryptoconditions Fulfillment needs to be present in the passed-in dictionary, as Condition URIs are not serializable anymore. Args: data (dict): The dict to be transformed. Returns: :class:`~bigchaindb.common.transaction.Output` """ try: fulfillment = Fulfillment.from_dict(data['condition']['details']) except KeyError: # NOTE: Hashlock condition case fulfillment = data['condition']['uri'] try: amount = int(data['amount']) except ValueError: raise AmountError('Invalid amount: %s' % data['amount']) return cls(fulfillment, data['public_keys'], amount)
def test_fulfillment_nested_and_or(self, fulfillment_sha256, fulfillment_ed25519, fulfillment_threshold_nested_and_or): ilp_fulfillment_sha = Fulfillment.from_uri( fulfillment_sha256['fulfillment_uri']) ilp_fulfillment_ed = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) # 2-of-2 (AND with 2 inputs) fulfillment = ThresholdSha256Fulfillment(threshold=2) fulfillment.add_subfulfillment(ilp_fulfillment_sha) assert fulfillment.validate(MESSAGE) is False # 1-of-2 (OR with 2 inputs) nested_fulfillment = ThresholdSha256Fulfillment(threshold=1) nested_fulfillment.add_subfulfillment(ilp_fulfillment_ed) assert nested_fulfillment.validate(MESSAGE) is True nested_fulfillment.add_subfulfillment(ilp_fulfillment_ed) assert nested_fulfillment.validate(MESSAGE) is True fulfillment.add_subfulfillment(nested_fulfillment) assert fulfillment.validate(MESSAGE) is True fulfillment_uri = fulfillment.serialize_uri() assert fulfillment.condition_uri == fulfillment_threshold_nested_and_or[ 'condition_uri'] assert fulfillment_uri == fulfillment_threshold_nested_and_or[ 'fulfillment_uri'] print(fulfillment_uri) deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri) condition_uri = fulfillment.condition.serialize_uri() deserialized_condition = Condition.from_uri(condition_uri) assert isinstance(deserialized_fulfillment, ThresholdSha256Fulfillment) assert deserialized_fulfillment.threshold == 2 assert len(deserialized_fulfillment.subconditions) == 2 assert len(deserialized_fulfillment.subconditions[1] ['body'].subconditions) == 2 assert deserialized_fulfillment.serialize_uri() == fulfillment_uri assert deserialized_fulfillment.validate(MESSAGE) assert deserialized_condition.serialize_uri() == condition_uri vk = ilp_fulfillment_ed.public_key.encode(encoding='base58') assert len(fulfillment.get_subcondition_from_vk(vk)) == 2 assert len(deserialized_fulfillment.get_subcondition_from_vk(vk)) == 1
def test_fulfillment_nested( self, fulfillment_sha256, fulfillment_ed25519_2, ): ilp_fulfillment_sha = Fulfillment.from_uri( fulfillment_sha256['fulfillment_uri']) ilp_fulfillment_ed1 = Fulfillment.from_uri( fulfillment_ed25519_2['fulfillment_uri']) # 2-of-2 (AND with 2 inputs) fulfillment = ThresholdSha256Fulfillment(threshold=2) fulfillment.add_subfulfillment(ilp_fulfillment_sha) max_depth = 6 def add_nested_fulfillment(parent, current_depth=0): current_depth += 1 child = ThresholdSha256Fulfillment(threshold=1) if current_depth < max_depth: add_nested_fulfillment(child, current_depth) else: child.add_subfulfillment(ilp_fulfillment_ed1) parent.add_subfulfillment(child) return parent fulfillment = add_nested_fulfillment(fulfillment) assert fulfillment.validate(MESSAGE) is True assert len(fulfillment.subconditions) == 2 assert isinstance(fulfillment.subconditions[1]['body'], ThresholdSha256Fulfillment) assert isinstance( fulfillment.subconditions[1]['body'].subconditions[0]['body'], ThresholdSha256Fulfillment) fulfillment_uri = fulfillment.serialize_uri() deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri) condition_uri = fulfillment.condition.serialize_uri() deserialized_condition = Condition.from_uri(condition_uri) assert deserialized_fulfillment.serialize_uri() == fulfillment_uri assert deserialized_fulfillment.validate(MESSAGE) is True assert deserialized_condition.serialize_uri() == condition_uri
def test_deserialize_and_validate_fulfillment(self, fulfillment_sha256): fulfillment = Fulfillment.from_uri( fulfillment_sha256['fulfillment_uri']) assert fulfillment.serialize_uri( ) == fulfillment_sha256['fulfillment_uri'] assert fulfillment.condition.serialize_uri( ) == fulfillment_sha256['condition_uri'] assert fulfillment.validate()
def test_deserialize_signed_dict_to_fulfillment(self, fulfillment_ed25519): fulfillment = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) parsed_fulfillment = fulfillment.from_dict(fulfillment.to_dict()) assert parsed_fulfillment.serialize_uri( ) == fulfillment_ed25519['fulfillment_uri'] assert parsed_fulfillment.condition.serialize_uri( ) == fulfillment.condition.serialize_uri() assert parsed_fulfillment.to_dict() == fulfillment.to_dict()
def test_fulfillment_nested_and_or(self, fulfillment_sha256, fulfillment_ed25519, fulfillment_threshold_nested_and_or): ilp_fulfillment_sha = Fulfillment.from_uri(fulfillment_sha256['fulfillment_uri']) ilp_fulfillment_ed = Fulfillment.from_uri(fulfillment_ed25519['fulfillment_uri']) # 2-of-2 (AND with 2 inputs) fulfillment = ThresholdSha256(threshold=2) fulfillment.add_subfulfillment(ilp_fulfillment_sha) assert fulfillment.validate(MESSAGE) is False # 1-of-2 (OR with 2 inputs) nested_fulfillment = ThresholdSha256(threshold=1) nested_fulfillment.add_subfulfillment(ilp_fulfillment_ed) assert nested_fulfillment.validate(MESSAGE) is True nested_fulfillment.add_subfulfillment(ilp_fulfillment_ed) assert nested_fulfillment.validate(MESSAGE) is True fulfillment.add_subfulfillment(nested_fulfillment) assert fulfillment.validate(MESSAGE) is True fulfillment_uri = fulfillment.serialize_uri() assert fulfillment.condition_uri == fulfillment_threshold_nested_and_or['condition_uri'] assert fulfillment_uri == fulfillment_threshold_nested_and_or['fulfillment_uri'] print(fulfillment_uri) deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri) condition_uri = fulfillment.condition.serialize_uri() deserialized_condition = Condition.from_uri(condition_uri) assert isinstance(deserialized_fulfillment, ThresholdSha256) assert deserialized_fulfillment.threshold == 2 assert len(deserialized_fulfillment.subconditions) == 2 assert len(deserialized_fulfillment.subconditions[1]['body'].subconditions) == 2 assert deserialized_fulfillment.serialize_uri() == fulfillment_uri assert deserialized_fulfillment.validate(MESSAGE) assert deserialized_condition.serialize_uri() == condition_uri vk = ilp_fulfillment_ed.public_key.encode(encoding='base58') assert len(fulfillment.get_subcondition_from_vk(vk)) == 2 assert len(deserialized_fulfillment.get_subcondition_from_vk(vk)) == 1
def test_fulfillment_serialize_to_dict(self, fulfillment_sha256): fulfillment = Fulfillment.from_uri( fulfillment_sha256['fulfillment_uri']) parsed_fulfillment = fulfillment.from_dict(fulfillment.to_dict()) assert parsed_fulfillment.serialize_uri() == fulfillment.serialize_uri( ) assert parsed_fulfillment.condition.serialize_uri( ) == fulfillment.condition.serialize_uri() assert parsed_fulfillment.to_dict() == fulfillment.to_dict()
def test_fulfillment_serialization(ffill_uri, user_pub): from bigchaindb_common.transaction import Fulfillment from cryptoconditions import Fulfillment as CCFulfillment expected = { 'owners_before': [user_pub], 'fulfillment': ffill_uri, 'input': None, } ffill = Fulfillment(CCFulfillment.from_uri(ffill_uri), [user_pub]) assert ffill.to_dict() == expected
def test_input_serialization(ffill_uri, user_pub): from bigchaindb.common.transaction import Input from cryptoconditions import Fulfillment expected = { 'owners_before': [user_pub], 'fulfillment': ffill_uri, 'fulfills': None, } input = Input(Fulfillment.from_uri(ffill_uri), [user_pub]) assert input.to_dict() == expected
def test_serialize_signed_dict_to_fulfillment(self, fulfillment_ed25519): fulfillment = Fulfillment.from_uri(fulfillment_ed25519['fulfillment_uri']) assert fulfillment.to_dict()== \ {'bitmask': 32, 'public_key': 'Gtbi6WQDB6wUePiZm8aYs5XZ5pUqx9jMMLvRVHPESTjU', 'signature': '4eCt6SFPCzLQSAoQGW7CTu3MHdLj6FezSpjktE7tHsYGJ4pNSUnpHtV9XgdHF2XYd62M9fTJ4WYdhTVck27qNoHj', 'type': 'fulfillment', 'type_id': 4} assert fulfillment.validate(MESSAGE) == True
def test_serialize_signed_dict_to_fulfillment(self, fulfillment_ed25519): fulfillment = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) assert fulfillment.to_dict()== \ {'bitmask': 32, 'public_key': 'Gtbi6WQDB6wUePiZm8aYs5XZ5pUqx9jMMLvRVHPESTjU', 'signature': '4eCt6SFPCzLQSAoQGW7CTu3MHdLj6FezSpjktE7tHsYGJ4pNSUnpHtV9XgdHF2XYd62M9fTJ4WYdhTVck27qNoHj', 'type': 'fulfillment', 'type_id': 4} assert fulfillment.validate(MESSAGE) == True
def test_serialize_condition_and_validate_fulfillment( self, fulfillment_sha256, fulfillment_ed25519): ilp_fulfillment_sha = Fulfillment.from_uri( fulfillment_sha256['fulfillment_uri']) ilp_fulfillment_ed = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) fulfillment_escrow = ThresholdSha256Fulfillment(threshold=1) fulfillment_timeout = TimeoutFulfillment( expire_time=str(float(timestamp()) + 1000)) fulfillment_timeout_inverted = InvertedThresholdSha256Fulfillment( threshold=1) fulfillment_timeout_inverted.add_subfulfillment(fulfillment_timeout) fulfillment_and_execute = ThresholdSha256Fulfillment(threshold=2) fulfillment_and_execute.add_subfulfillment(ilp_fulfillment_ed) fulfillment_and_execute.add_subfulfillment(fulfillment_timeout) assert fulfillment_and_execute.validate(MESSAGE, now=timestamp()) is True fulfillment_and_abort = ThresholdSha256Fulfillment(threshold=2) fulfillment_and_abort.add_subfulfillment(ilp_fulfillment_sha) fulfillment_and_abort.add_subfulfillment(fulfillment_timeout_inverted) # timeout has not occured (over about 1000 seconds) assert fulfillment_and_abort.validate(MESSAGE, now=timestamp()) is False fulfillment_escrow.add_subfulfillment(fulfillment_and_execute) fulfillment_escrow.add_subfulfillment(fulfillment_and_abort) parsed_fulfillment = fulfillment_escrow.from_dict( fulfillment_escrow.to_dict()) assert parsed_fulfillment.condition_uri == fulfillment_escrow.condition_uri assert parsed_fulfillment.serialize_uri( ) == fulfillment_escrow.serialize_uri() assert parsed_fulfillment.validate(MESSAGE, now=timestamp()) is True
def test_deserialize_fulfillment(self, vk_ilp, fulfillment_ed25519): fulfillment = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) assert isinstance(fulfillment, Ed25519Fulfillment) assert fulfillment.serialize_uri( ) == fulfillment_ed25519['fulfillment_uri'] assert fulfillment.condition.serialize_uri( ) == fulfillment_ed25519['condition_uri'] assert binascii.hexlify(fulfillment.condition.hash ) == fulfillment_ed25519['condition_hash'] assert fulfillment.public_key.encode(encoding='hex') == vk_ilp['hex'] assert fulfillment.validate(MESSAGE)
def test_fulfillment_didnt_reach_threshold(self, vk_ilp, fulfillment_ed25519): ilp_fulfillment = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) threshold = 10 # Create a threshold condition fulfillment = ThresholdSha256Fulfillment(threshold=threshold) for i in range(threshold - 1): fulfillment.add_subfulfillment(ilp_fulfillment) with pytest.raises(KeyError): fulfillment.serialize_uri() assert fulfillment.validate(MESSAGE) is False fulfillment.add_subfulfillment(ilp_fulfillment) fulfillment_uri = fulfillment.serialize_uri() assert fulfillment.validate(MESSAGE) deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri) assert isinstance(deserialized_fulfillment, ThresholdSha256Fulfillment) assert deserialized_fulfillment.threshold == threshold assert len([ f for f in deserialized_fulfillment.subconditions if f['type'] == 'fulfillment' ]) == threshold assert len(deserialized_fulfillment.subconditions) == threshold assert deserialized_fulfillment.serialize_uri() == fulfillment_uri assert deserialized_fulfillment.validate(MESSAGE) fulfillment.add_subfulfillment( Ed25519Fulfillment(public_key=VerifyingKey(vk_ilp['b58']))) assert fulfillment.validate(MESSAGE) == True
def test_fulfillment_nested(self, fulfillment_sha256, fulfillment_ed25519_2, ): ilp_fulfillment_sha = Fulfillment.from_uri(fulfillment_sha256['fulfillment_uri']) ilp_fulfillment_ed1 = Fulfillment.from_uri(fulfillment_ed25519_2['fulfillment_uri']) # 2-of-2 (AND with 2 inputs) fulfillment = ThresholdSha256(threshold=2) fulfillment.add_subfulfillment(ilp_fulfillment_sha) max_depth = 6 def add_nested_fulfillment(parent, current_depth=0): current_depth += 1 child = ThresholdSha256(threshold=1) if current_depth < max_depth: add_nested_fulfillment(child, current_depth) else: child.add_subfulfillment(ilp_fulfillment_ed1) parent.add_subfulfillment(child) return parent fulfillment = add_nested_fulfillment(fulfillment) assert fulfillment.validate(MESSAGE) is True assert len(fulfillment.subconditions) == 2 assert isinstance(fulfillment.subconditions[1]['body'], ThresholdSha256) assert isinstance(fulfillment.subconditions[1]['body'].subconditions[0]['body'], ThresholdSha256) fulfillment_uri = fulfillment.serialize_uri() deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri) condition_uri = fulfillment.condition.serialize_uri() deserialized_condition = Condition.from_uri(condition_uri) assert deserialized_fulfillment.serialize_uri() == fulfillment_uri assert deserialized_fulfillment.validate(MESSAGE) is True assert deserialized_condition.serialize_uri() == condition_uri
def verify_signature(): if request.method == 'POST': request_json = json.loads(request.get_data()) # print(request_json['message']) request_json['type'] = 'ed25519-sha-256' fulfillment_object = Fulfillment.from_dict(request_json) encoded_message = sha3_256(request_json['message'].encode()).digest() # print(request_json['hash']) decoded_message = bytes.fromhex(request_json['hash']) # response = {"result": fulfillment_object.validate(message=encoded_message)} response = { "result": fulfillment_object.validate(message=decoded_message) } return json.dumps(response)
def test_fulfill_transaction(alice_transaction, alice_sk): from bigchaindb_driver.offchain import fulfill_transaction fulfilled_transaction = fulfill_transaction(alice_transaction, private_keys=alice_sk) inputs = fulfilled_transaction['inputs'] assert len(inputs) == 1 alice_transaction['inputs'][0]['fulfillment'] = None message = rapidjson.dumps( alice_transaction, skipkeys=False, ensure_ascii=False, sort_keys=True, ).encode() fulfillment_uri = inputs[0]['fulfillment'] assert Fulfillment.from_uri(fulfillment_uri).validate(message=message)
def _input_valid(self, input_, operation, message, output_condition_uri=None): """Validates a single Input against a single Output. Note: In case of a `CREATE` Transaction, this method does not validate against `output_condition_uri`. Args: input_ (:class:`~bigchaindb.common.transaction. Input`) The Input to be signed. operation (str): The type of Transaction. message (str): The fulfillment message. output_condition_uri (str, optional): An Output to check the Input against. Returns: bool: If the Input is valid. """ ccffill = input_.fulfillment try: parsed_ffill = Fulfillment.from_uri(ccffill.serialize_uri()) except (TypeError, ValueError, ParsingError, ASN1DecodeError, ASN1EncodeError): return False if operation == self.CREATE: # NOTE: In the case of a `CREATE` transaction, the # output is always valid. output_valid = True else: output_valid = output_condition_uri == ccffill.condition_uri message = sha3_256(message.encode()) if input_.fulfills: message.update('{}{}'.format(input_.fulfills.txid, input_.fulfills.output).encode()) # NOTE: We pass a timestamp to `.validate`, as in case of a timeout # condition we'll have to validate against it # cryptoconditions makes no assumptions of the encoding of the # message to sign or verify. It only accepts bytestrings ffill_valid = parsed_ffill.validate(message=message.digest()) return output_valid and ffill_valid
def test_serialize_condition_and_validate_fulfillment( self, fulfillment_ed25519): ilp_fulfillment_ed = Fulfillment.from_uri( fulfillment_ed25519['fulfillment_uri']) fulfillment = InvertedThresholdSha256Fulfillment(threshold=1) fulfillment.add_subfulfillment(ilp_fulfillment_ed) parsed_fulfillment = fulfillment.from_dict(fulfillment.to_dict()) assert parsed_fulfillment.condition_uri == fulfillment.condition_uri assert parsed_fulfillment.serialize_uri() == fulfillment.serialize_uri( ) assert parsed_fulfillment.validate(MESSAGE) is False assert parsed_fulfillment.validate() is True assert isinstance(parsed_fulfillment, InvertedThresholdSha256Fulfillment)
def test_deserialize_fulfillment(self, fulfillment_threshold): num_fulfillments = 2 threshold = 1 fulfillment = Fulfillment.from_uri( fulfillment_threshold['fulfillment_uri']) assert isinstance(fulfillment, ThresholdSha256Fulfillment) assert fulfillment.threshold == threshold assert len([ f for f in fulfillment.subconditions if f['type'] == 'fulfillment' ]) == threshold assert fulfillment.serialize_uri( ) == fulfillment_threshold['fulfillment_uri'] assert len(fulfillment.subconditions) == num_fulfillments assert fulfillment.validate(MESSAGE)
def _input_valid(input_, operation, tx_serialized, output_condition_uri=None): """Validates a single Input against a single Output. Note: In case of a `CREATE` or `GENESIS` Transaction, this method does not validate against `output_condition_uri`. Args: input_ (:class:`~bigchaindb.common.transaction. Input`) The Input to be signed. operation (str): The type of Transaction. tx_serialized (str): The Transaction used as a message when initially signing it. output_condition_uri (str, optional): An Output to check the Input against. Returns: bool: If the Input is valid. """ ccffill = input_.fulfillment try: parsed_ffill = Fulfillment.from_uri(ccffill.serialize_uri()) except (TypeError, ValueError, ParsingError, ASN1DecodeError, ASN1EncodeError): return False if operation in (Transaction.CREATE, Transaction.GENESIS): # NOTE: In the case of a `CREATE` or `GENESIS` transaction, the # output is always valid. output_valid = True else: output_valid = output_condition_uri == ccffill.condition_uri # NOTE: We pass a timestamp to `.validate`, as in case of a timeout # condition we'll have to validate against it # cryptoconditions makes no assumptions of the encoding of the # message to sign or verify. It only accepts bytestrings try: # the validation of RSA in cryptoconditions should return a boolean # but instead raises and exception in case of an invalid signature ffill_valid = parsed_ffill.validate(message=tx_serialized.encode()) except ValidationError: ffill_valid = False return output_valid and ffill_valid
def verify(reading_id): transaction = transactions.find_one({"id": reading_id}) reading = collection.find_one({"id": reading_id}) formatted_reading = format_reading(reading) public_key = transaction['outputs'][0]['condition']['details'][ 'public_key'] uri = transaction['outputs'][0]['condition']['uri'] fulfillment = Fulfillment.from_uri( transaction['inputs'][0]['fulfillment']).to_dict() print(fulfillment) signature = fulfillment['signature'] message = generate_message(reading['data'], public_key, uri) return json.dumps({ "reading": formatted_reading, "message": str(message), "public_key": str(public_key), "signature": str(signature) })
def CREATETransactionFromDict(cls, dictionary): transaction = Transaction() try: if dictionary["data"]["condition"][ "type"] == Ed25519Sha256.TYPE_NAME: transaction.condition = dictionary['data']["condition_uri"] elif dictionary["data"]["condition"][ "type"] == ThresholdSha256.TYPE_NAME: transaction.condition = dictionary['data']["condition_uri"] else: raise InvalidCreateTransaction() transaction.fulfillment = Fulfillment.from_uri( dictionary["data"]["fulfillment"]["fulfillment_uri"]) transaction.id = dictionary["id"] except: raise InvalidCreateTransaction() return transaction
def _input_valid(input_, operation, message, output_condition_uri=None): """Validates a single Input against a single Output. Note: In case of a `CREATE` or `GENESIS` Transaction, this method does not validate against `output_condition_uri`. Args: input_ (:class:`~bigchaindb.common.transaction. Input`) The Input to be signed. operation (str): The type of Transaction. message (str): The fulfillment message. output_condition_uri (str, optional): An Output to check the Input against. Returns: bool: If the Input is valid. """ ccffill = input_.fulfillment try: parsed_ffill = Fulfillment.from_uri(ccffill.serialize_uri()) except (TypeError, ValueError, ParsingError, ASN1DecodeError, ASN1EncodeError): return False if operation in (Transaction.CREATE, Transaction.GENESIS): # NOTE: In the case of a `CREATE` or `GENESIS` transaction, the # output is always valid. output_valid = True else: output_valid = output_condition_uri == ccffill.condition_uri message = sha3_256(message.encode()) if input_.fulfills: message.update('{}{}'.format( input_.fulfills.txid, input_.fulfills.output).encode()) # NOTE: We pass a timestamp to `.validate`, as in case of a timeout # condition we'll have to validate against it # cryptoconditions makes no assumptions of the encoding of the # message to sign or verify. It only accepts bytestrings ffill_valid = parsed_ffill.validate(message=message.digest()) return output_valid and ffill_valid
def test_serialize_signed_dict_to_fulfillment(self, fulfillment_threshold): fulfillment = Fulfillment.from_uri(fulfillment_threshold['fulfillment_uri']) assert fulfillment.to_dict() == \ {'bitmask': 43, 'subfulfillments': [{'bitmask': 3, 'preimage': '', 'type': 'fulfillment', 'type_id': 0, 'weight': 1}, {'bitmask': 32, 'hash': 'Gtbi6WQDB6wUePiZm8aYs5XZ5pUqx9jMMLvRVHPESTjU', 'max_fulfillment_length': 96, 'type': 'condition', 'type_id': 4, 'weight': 1}], 'threshold': 1, 'type': 'fulfillment', 'type_id': 2}
def test_serialize_deserialize_fulfillment(self, sk_ilp, vk_ilp): sk = SigningKey(sk_ilp['b58']) vk = VerifyingKey(vk_ilp['b58']) fulfillment = Ed25519Fulfillment(public_key=vk) fulfillment.sign(MESSAGE, sk) assert fulfillment.validate(MESSAGE) deserialized_fulfillment = Fulfillment.from_uri( fulfillment.serialize_uri()) assert isinstance(deserialized_fulfillment, Ed25519Fulfillment) assert deserialized_fulfillment.serialize_uri( ) == fulfillment.serialize_uri() assert deserialized_fulfillment.condition.serialize_uri( ) == fulfillment.condition.serialize_uri() assert deserialized_fulfillment.public_key.encode(encoding='bytes') == \ fulfillment.public_key.encode(encoding='bytes') assert deserialized_fulfillment.validate(MESSAGE)
def _input_valid(input_, operation, tx_serialized, output_condition_uri=None): """Validates a single Input against a single Output. Note: In case of a `CREATE` or `GENESIS` Transaction, this method does not validate against `output_condition_uri`. Args: input_ (:class:`~bigchaindb.common.transaction. Input`) The Input to be signed. operation (str): The type of Transaction. tx_serialized (str): The Transaction used as a message when initially signing it. output_condition_uri (str, optional): An Output to check the Input against. Returns: bool: If the Input is valid. """ ccffill = input_.fulfillment try: parsed_ffill = Fulfillment.from_uri(ccffill.serialize_uri()) except (TypeError, ValueError, ParsingError, ASN1DecodeError, ASN1EncodeError): return False if operation in (Transaction.CREATE, Transaction.GENESIS): # NOTE: In the case of a `CREATE` or `GENESIS` transaction, the # output is always valid. output_valid = True else: output_valid = output_condition_uri == ccffill.condition_uri # NOTE: We pass a timestamp to `.validate`, as in case of a timeout # condition we'll have to validate against it # cryptoconditions makes no assumptions of the encoding of the # message to sign or verify. It only accepts bytestrings ffill_valid = parsed_ffill.validate(message=tx_serialized.encode()) return output_valid and ffill_valid
def from_dict(cls, cond): """Transforms a Python dictionary to a Condition object. Note: To pass a serialization cycle multiple times, a Cryptoconditions Fulfillment needs to be present in the passed-in dictionary, as Condition URIs are not serializable anymore. Args: cond (dict): The Condition to be transformed. Returns: :class:`~bigchaindb.common.transaction.Condition` """ try: fulfillment = CCFulfillment.from_dict(cond['condition']['details']) except KeyError: # NOTE: Hashlock condition case fulfillment = cond['condition']['uri'] return cls(fulfillment, cond['owners_after'], cond['amount'])
def _fulfillment_valid(fulfillment, operation, tx_serialized, input_condition_uri=None): """Validates a single Fulfillment against a single Condition. Note: In case of a `CREATE` or `GENESIS` Transaction, this method does not validate against `input_condition_uri`. Args: fulfillment (:class:`~bigchaindb.common.transaction. Fulfillment`) The Fulfillment to be signed. operation (str): The type of Transaction. tx_serialized (str): The Transaction used as a message when initially signing it. input_condition_uri (str, optional): A Condition to check the Fulfillment against. Returns: bool: If the Fulfillment is valid. """ ccffill = fulfillment.fulfillment try: parsed_ffill = CCFulfillment.from_uri(ccffill.serialize_uri()) except (TypeError, ValueError, ParsingError): return False if operation in (Transaction.CREATE, Transaction.GENESIS): # NOTE: In the case of a `CREATE` or `GENESIS` transaction, the # input condition is always validate to `True`. input_cond_valid = True else: input_cond_valid = input_condition_uri == ccffill.condition_uri # NOTE: We pass a timestamp to `.validate`, as in case of a timeout # condition we'll have to validate against it # cryptoconditions makes no assumptions of the encoding of the # message to sign or verify. It only accepts bytestrings return parsed_ffill.validate(message=tx_serialized.encode(), now=gen_timestamp()) and input_cond_valid
def test_from_uri_with_invalid_type(self): from cryptoconditions import Fulfillment with pytest.raises(TypeError) as exc: Fulfillment.from_uri(123) assert exc.value.args == ('Serialized fulfillment must be a string',)
def test_condition_binary(self, test_vector): from cryptoconditions import Fulfillment fulfillment = Fulfillment.from_uri(test_vector.fulfillment) assert fulfillment.condition_binary == test_vector.condition_binary