def test_serialize_unsigned_dict_to_fulfillment(self, vk_ilp): fulfillment = Ed25519Sha256(public_key=vk_ilp['b58']) assert fulfillment.to_dict() == \ {'bitmask': 32, 'public_key': 'Gtbi6WQDB6wUePiZm8aYs5XZ5pUqx9jMMLvRVHPESTjU', 'signature': None, 'type': 'fulfillment', 'type_id': 4} assert fulfillment.validate(MESSAGE) == False
def make_ed25519_condition(public_key, *, amount=1): ed25519 = Ed25519Sha256(public_key=base58.b58decode(public_key)) return { 'amount': str(amount), 'condition': { 'details': _fulfillment_to_details(ed25519), 'uri': ed25519.condition_uri, }, 'public_keys': (public_key, ), }
def sign_transaction(transaction, *, public_key, private_key): ed25519 = Ed25519Sha256(public_key=base58.b58decode(public_key)) message = json.dumps( transaction, sort_keys=True, separators=(',', ':'), ensure_ascii=False, ) ed25519.sign(message.encode(), base58.b58decode(private_key)) return ed25519.serialize_uri()
def test_validate_tx_threshold_duplicated_pk(user_pub, user_priv, asset_definition): from cryptoconditions import Ed25519Sha256, ThresholdSha256 from bigchaindb.common.transaction import Input, Output, Transaction threshold = ThresholdSha256(threshold=2) threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub))) threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub))) threshold_input = Input(threshold, [user_pub, user_pub]) threshold_output = Output(threshold, [user_pub, user_pub]) tx = Transaction(Transaction.CREATE, asset_definition, [threshold_input], [threshold_output]) tx_dict = tx.to_dict() tx_dict['inputs'][0]['fulfillment'] = None serialized_tx = json.dumps(tx_dict, sort_keys=True, separators=(',', ':'), ensure_ascii=True) message = sha3_256(serialized_tx.encode()).digest() expected = deepcopy(threshold_input) expected.fulfillment.subconditions[0]['body'].sign(message, b58decode(user_priv)) expected.fulfillment.subconditions[1]['body'].sign(message, b58decode(user_priv)) tx.sign([user_priv, user_priv]) subconditions = tx.inputs[0].fulfillment.subconditions expected_subconditions = expected.fulfillment.subconditions assert subconditions[0]['body'].to_dict()['signature'] == \ expected_subconditions[0]['body'].to_dict()['signature'] assert subconditions[1]['body'].to_dict()['signature'] == \ expected_subconditions[1]['body'].to_dict()['signature'] assert tx.inputs[0].to_dict()['fulfillment'] == \ expected.fulfillment.serialize_uri() assert tx.inputs_valid() is True
def sign_ed25519(transaction, private_keys): from cryptoconditions import Ed25519Sha256 from cryptoconditions.crypto import Ed25519VerifyingKey for index, _input in enumerate(transaction.inputs): receiver = _input.owners_before[0] transaction.inputs[index].fulfillment = Ed25519Sha256( public_key=Ed25519VerifyingKey(receiver).encode('bytes')) private_keys = [private_keys ] if not isinstance(private_keys, list) else private_keys return transaction.sign(private_keys).to_dict()
def test_non_create_input_not_found(self, b, user_pk): from cryptoconditions import Ed25519Sha256 from bigchaindb.common.exceptions import InputDoesNotExist from bigchaindb.common.transaction import Input, TransactionLink from bigchaindb.models import Transaction # Create an input for a non existing transaction input = Input(Ed25519Sha256(public_key=b58decode(user_pk)), [user_pk], TransactionLink('somethingsomething', 0)) tx = Transaction.transfer([input], [([user_pk], 1)], asset_id='mock_asset_link') with pytest.raises(InputDoesNotExist): tx.validate(b)
def generate_service(service_key, owner_keys, auth_keys=[], owners_authorize=True): """ create a an unsigned service msg Args: service_keys ([str])- service denoted by base58 encoded keys owner_keys ([str]) - public keys recognizing ownership of the services and therefore administrators auth_keys ([str])- those who can give access to a resource. Generally owners must also be authorizers returns: a message without any signature or identity resolution """ message = MessageShell.messageForType(MSGTYPE.REGISTER) message['data']['service'] = service_key message['data']['owners'] = owner_keys if owners_authorize: message['data']['authorities'] = owner_keys + auth_keys else: message['data']['authorities'] = auth_keys condition = None if len(owner_keys) != 1: condition = ThresholdSha256(threshold=len(owner_keys)) for key in owner_keys: condition.add_subfulfillment( Ed25519Sha256(public_key=base58.b58decode(key))) else: condition = Ed25519Sha256(public_key=base58.b58decode(owner_keys[0])) message['data']['condition'] = condition.to_dict() message['data']['condition_uri'] = condition.condition_uri message['data']['fulfillment'] = None message['id'] = None return message
def test_fulfill(self, driver, alice_keypair, unsigned_transaction): signed_transaction = driver.transactions.fulfill( unsigned_transaction, private_keys=alice_keypair.sk) unsigned_transaction['inputs'][0]['fulfillment'] = None message = json.dumps( unsigned_transaction, sort_keys=True, separators=(',', ':'), ensure_ascii=False, ) message = sha3_256(message.encode()) ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice_keypair.vk)) ed25519.sign(message.digest(), base58.b58decode(alice_keypair.sk)) fulfillment_uri = ed25519.serialize_uri() assert signed_transaction['inputs'][0]['fulfillment'] == fulfillment_uri # noqa
def test_serialize_unsigned_dict_to_fulfillment(self, vk_ilp): fulfillment = ThresholdSha256(threshold=1) fulfillment.add_subfulfillment( Ed25519Sha256(public_key=VerifyingKey(vk_ilp['b58']))) fulfillment.add_subfulfillment( Ed25519Sha256(public_key=VerifyingKey(vk_ilp['b58']))) assert fulfillment.to_dict() == \ {'bitmask': 41, 'subfulfillments': [{'bitmask': 32, 'public_key': 'Gtbi6WQDB6wUePiZm8aYs5XZ5pUqx9jMMLvRVHPESTjU', 'signature': None, 'type': 'fulfillment', 'type_id': 4, 'weight': 1}, {'bitmask': 32, 'public_key': 'Gtbi6WQDB6wUePiZm8aYs5XZ5pUqx9jMMLvRVHPESTjU', 'signature': None, 'type': 'fulfillment', 'type_id': 4, 'weight': 1}], 'threshold': 1, 'type': 'fulfillment', 'type_id': 2}
def generate(cls, public_keys, amount): """Generates a Output from a specifically formed tuple or list. Note: If a ThresholdCondition has to be generated where the threshold is always the number of subconditions it is split between, a list of the following structure is sufficient: [(address|condition)*, [(address|condition)*, ...], ...] Args: public_keys (:obj:`list` of :obj:`str`): The public key of the users that should be able to fulfill the Condition that is being created. amount (:obj:`int`): The amount locked by the Output. Returns: An Output that can be used in a Transaction. Raises: TypeError: If `public_keys` is not an instance of `list`. ValueError: If `public_keys` is an empty list. """ threshold = len(public_keys) if not isinstance(amount, int): raise TypeError('`amount` must be a int') if amount < 1: raise AmountError('`amount` needs to be greater than zero') if not isinstance(public_keys, list): raise TypeError('`public_keys` must be an instance of list') if len(public_keys) == 0: raise ValueError('`public_keys` needs to contain at least one' 'owner') elif len(public_keys) == 1 and not isinstance(public_keys[0], list): if isinstance(public_keys[0], Fulfillment): ffill = public_keys[0] else: ffill = Ed25519Sha256( public_key=base58.b58decode(public_keys[0])) return cls(ffill, public_keys, amount=amount) else: initial_cond = ThresholdSha256(threshold=threshold) threshold_cond = reduce(cls._gen_condition, public_keys, initial_cond) return cls(threshold_cond, public_keys, amount=amount)
def _gen_condition(cls, initial, new_public_keys): """Generates ThresholdSha256 conditions from a list of new owners. Note: This method is intended only to be used with a reduce function. For a description on how to use this method, see :meth:`~.Output.generate`. Args: initial (:class:`cryptoconditions.ThresholdSha256`): A Condition representing the overall root. new_public_keys (:obj:`list` of :obj:`str`|str): A list of new owners or a single new owner. Returns: :class:`cryptoconditions.ThresholdSha256`: """ try: threshold = len(new_public_keys) except TypeError: threshold = None if isinstance(new_public_keys, list) and len(new_public_keys) > 1: ffill = ThresholdSha256(threshold=threshold) reduce(cls._gen_condition, new_public_keys, ffill) elif isinstance(new_public_keys, list) and len(new_public_keys) <= 1: raise ValueError('Sublist cannot contain single owner') else: try: new_public_keys = new_public_keys.pop() except AttributeError: pass # NOTE: Instead of submitting base58 encoded addresses, a user # of this class can also submit fully instantiated # Cryptoconditions. In the case of casting # `new_public_keys` to a Ed25519Fulfillment with the # result of a `TypeError`, we're assuming that # `new_public_keys` is a Cryptocondition then. if isinstance(new_public_keys, Fulfillment): ffill = new_public_keys else: ffill = Ed25519Sha256( public_key=base58.b58decode(new_public_keys)) initial.add_subfulfillment(ffill) return initial
def prepare_transfer_ed25519_simple(transaction, receiver, metadata=None): from cryptoconditions import Ed25519Sha256 from cryptoconditions.crypto import Ed25519VerifyingKey return prepare_transfer( inputs=[{ 'tx': transaction, 'output': 0 }], outputs=[{ 'condition': Ed25519Sha256( public_key=Ed25519VerifyingKey(receiver).encode('bytes')), 'public_keys': [receiver], 'amount': 1 }], metadata=metadata)
def test_validate_inputs_of_transfer_tx_with_invalid_params( transfer_tx, cond_uri, utx, user2_pub, user_priv, ffill_uri): from bigchaindb.common.transaction import Output from cryptoconditions import Ed25519Sha256 invalid_out = Output(Ed25519Sha256.from_uri(ffill_uri), ['invalid']) assert transfer_tx.inputs_valid([invalid_out]) is False invalid_out = utx.outputs[0] invalid_out.public_key = 'invalid' assert transfer_tx.inputs_valid([invalid_out]) is True with raises(TypeError): assert transfer_tx.inputs_valid(None) is False with raises(AttributeError): transfer_tx.inputs_valid('not a list') with raises(ValueError): transfer_tx.inputs_valid([]) with raises(TypeError): transfer_tx.operation = "Operation that doesn't exist" transfer_tx.inputs_valid([utx.outputs[0]])
def _fulfillment_from_details(data, _depth=0): """Load a fulfillment for a signing spec dictionary Args: data: tx.output[].condition.details dictionary """ if _depth == 100: raise ThresholdTooDeep() if data['type'] == 'ed25519-sha-256': public_key = base58.b58decode(data['public_key']) return Ed25519Sha256(public_key=public_key) if data['type'] == 'threshold-sha-256': threshold = ThresholdSha256(data['threshold']) for cond in data['subconditions']: cond = _fulfillment_from_details(cond, _depth+1) threshold.add_subfulfillment(cond) return threshold raise UnsupportedTypeError(data.get('type'))
def test_post_create_transaction_with_invalid_schema(mock_logger, client): from bigchaindb.models import Transaction user_priv, user_pub = crypto.generate_key_pair() tx = Transaction.create([user_pub], [([user_pub], 1)]).to_dict() del tx['version'] ed25519 = Ed25519Sha256(public_key=base58.b58decode(user_pub)) message = json.dumps( tx, sort_keys=True, separators=(',', ':'), ensure_ascii=False, ).encode() ed25519.sign(message, base58.b58decode(user_priv)) tx['inputs'][0]['fulfillment'] = ed25519.serialize_uri() tx['id'] = sha3_256( json.dumps( tx, sort_keys=True, separators=(',', ':'), ensure_ascii=False, ).encode(), ).hexdigest() res = client.post(TX_ENDPOINT, data=json.dumps(tx)) expected_status_code = 400 expected_error_message = ( "Invalid transaction schema: 'version' is a required property") assert res.status_code == expected_status_code assert res.json['message'] == expected_error_message assert mock_logger.error.called assert ( 'HTTP API error: %(status)s - %(method)s:%(path)s - %(message)s' in mock_logger.error.call_args[0] ) assert ( { 'message': expected_error_message, 'status': expected_status_code, 'method': 'POST', 'path': TX_ENDPOINT } in mock_logger.error.call_args[0] )
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
operation = 'CREATE' version = '2.0' asset = { 'data': { 'bicycle': { 'manufacturer': 'bkfab', 'serial_number': 'abcd1234', }, }, } metadata = {'planet': 'earth'} ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key)) output = { 'amount': '1', 'condition': { 'details': { 'type': ed25519.TYPE_NAME, 'public_key': base58.b58encode(ed25519.public_key).decode(), }, 'uri': ed25519.condition_uri, }, 'public_keys': (alice.public_key, ), } outputs = (output, ) input_ = {
metadata = {'Units': 2400, 'Type': 'g'} # IPDB transaction schema version version = '2.0' # Policies written in Zencode - see https://github.com/DECODEproject/Zenroom # To apply it it has to be given as a parameter in line 95. script = """Scenario 'coconut': "To run over the mobile wallet the first time and store the output as keypair.keys" Given that I am known as 'identifier' When I create my new keypair Then print all data """ # CRYPTO-CONDITIONS: instantiate an Ed25519 crypto-condition for buyer ed25519 = Ed25519Sha256(public_key=base58.b58decode(producer.public_key)) # CRYPTO-CONDITIONS: generate the condition uri condition_uri = ed25519.condition.serialize_uri() # CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary unsigned_fulfillment_dict = { 'type': ed25519.TYPE_NAME, 'public_key': base58.b58encode(ed25519.public_key).decode(), } output = { 'amount': '2400', 'condition': { 'details': unsigned_fulfillment_dict, 'uri': condition_uri,
def user2_Ed25519(user2_pub): from cryptoconditions import Ed25519Sha256 return Ed25519Sha256(public_key=b58decode(user2_pub))
def test_permission_add_role(b): from .utils import create_simple_tx, post_tx, transfer_simple_tx, prepare_transfer, get_message_to_sign from bigchaindb.models import Transaction from cryptoconditions import ThresholdSha256, Ed25519Sha256, PreimageSha256 from cryptoconditions.crypto import Ed25519VerifyingKey, Ed25519SigningKey # admin, albi, bruce admin_priv, admin_pub = crypto.generate_key_pair() albi_priv, albi_pub = crypto.generate_key_pair() bruce_priv, bruce_pub = crypto.generate_key_pair() assert len(b.get_owned_ids(admin_pub)) == 0 assert len(b.get_owned_ids(albi_pub)) == 0 assert len(b.get_owned_ids(bruce_pub)) == 0 # admin CREATES role: tx_create_role, 202 tx_create_role = Transaction.create( [admin_pub], [([admin_pub], 1)], asset={ "policy": [ { "condition": "transaction.operation == 'TRANSFER'", "rule": "transaction.inputs[0].owners_before[0] == '{}'".format( admin_pub) }, ] }) # trick to not include in balance part 1 tx_create_role.outputs[0].public_keys = [] tx_create_role = tx_create_role.sign([admin_priv]) response = post_tx(b, None, tx_create_role) tx_create_role_retrieved = b.get_transaction(tx_create_role.id) assert response.status_code == 202 assert tx_create_role_retrieved.id == tx_create_role.id # admin.unspents = [] # admin doesnt have role, only created it # user_a.unspents = [] # user_a has no role # user_b.unspents = [] # user_b has no role assert len(b.get_owned_ids(admin_pub)) == 0 assert len(b.get_owned_ids(albi_pub)) == 0 assert len(b.get_owned_ids(bruce_pub)) == 0 # admin TRANSFERS tx_create_role TO user_a: tx_transfer_role_a, 202 # tx_transfer_role_a = Transaction.transfer( # [ # Input( # fulfillment=Ed25519Sha256( # public_key=b58decode(admin_pub)), # owners_before=[admin_pub], # trick to not include in balance part 2 # fulfills=TransactionLink( # txid=tx_create_role.id, # output=0) # ) # ], # [([albi_pub], 1)], # tx_create_role.id) # tx_transfer_role_a = tx_transfer_role_a.sign([admin_priv]) output_condition = ThresholdSha256(threshold=1) output_condition.add_subfulfillment( Ed25519Sha256(public_key=b58decode(admin_pub))) output_condition.add_subfulfillment( Ed25519Sha256(public_key=b58decode(albi_pub))) tx_transfer_role_a = prepare_transfer(inputs=[{ 'tx': tx_create_role.to_dict(), 'output': 0 }], outputs=[ { 'condition': output_condition, 'public_keys': [albi_pub] }, ]) input_fulfillment = Ed25519Sha256(public_key=b58decode(admin_pub)) tx_transfer_role_a.inputs[0].owners_before = [admin_pub] message_to_sign = get_message_to_sign(tx_transfer_role_a) input_fulfillment.sign(message_to_sign, b58decode(admin_priv)) tx_transfer_role_a.inputs[0].fulfillment = input_fulfillment tx_transfer_role_a.validate(b) response = post_tx(b, None, tx_transfer_role_a) # tx_create_role_retrieved = b.get_transaction(tx_create_role.id) assert response.status_code == 202 # user_a.unspents = [tx_transfer_role_a] # user_a has role assert len(b.get_owned_ids(admin_pub)) == 0 assert len(b.get_owned_ids(albi_pub)) == 1 assert len(b.get_owned_ids(bruce_pub)) == 0 # user TRANSFERS tx_transfer_role_a TO user_b: -, 400 # only admin can assign role tx_transfer_role_b = prepare_transfer( inputs=[{ 'tx': tx_transfer_role_a.to_dict(), 'output': 0 }], outputs=[ { 'condition': Ed25519Sha256(public_key=b58decode(bruce_pub)), }, ]) tx_transfer_role_b.inputs[0].owners_before = [albi_pub] message_to_sign = get_message_to_sign(tx_transfer_role_b) input_fulfillment = ThresholdSha256(threshold=1) albi_fulfillment = Ed25519Sha256(public_key=b58decode(albi_pub)) albi_fulfillment.sign(message_to_sign, b58decode(albi_priv)) input_fulfillment.add_subfulfillment(albi_fulfillment) input_fulfillment.add_subcondition( Ed25519Sha256(public_key=b58decode(admin_pub)).condition_uri) tx_transfer_role_b.inputs[0].fulfillment = input_fulfillment input_fulfillment.serialize_uri() tx_transfer_role_b.validate(b) response = post_tx(b, None, tx_transfer_role_b) assert response.status_code == 202 # user_a.unspents = [tx_transfer_role_a] # user_a has role # user_b.unspents = [] # user_b has no role assert len(b.get_owned_ids(admin_pub)) == 0 assert len(b.get_owned_ids(albi_pub)) == 0 assert len(b.get_owned_ids(bruce_pub)) == 0