def test_three():
    hash_0 = b'a' * 32
    hash_1 = b'b' * 32
    hash_2 = b'c' * 32

    leaves = [hash_0, hash_1, hash_2]
    layers = compute_layers(leaves)
    tree = MerkleTreeState(layers)
    root = merkleroot(tree)

    hash_01 = (
        b'me\xef\x9c\xa9=5\x16\xa4\xd3\x8a\xb7\xd9\x89\xc2\xb5\x00'
        b'\xe2\xfc\x89\xcc\xdc\xf8x\xf9\xc4m\xaa\xf6\xad\r['
    )
    assert sha3(hash_0 + hash_1) == hash_01
    calculated_root = sha3(hash_2 + hash_01)

    proof0 = compute_merkleproof_for(tree, hash_0)
    proof1 = compute_merkleproof_for(tree, hash_1)
    proof2 = compute_merkleproof_for(tree, hash_2)

    assert proof0 == [hash_1, hash_2]
    assert root == calculated_root
    assert validate_proof(proof0, root, hash_0)

    assert proof1 == [hash_0, hash_2]
    assert root == calculated_root
    assert validate_proof(proof1, root, hash_1)

    # with an odd number of values, the last value wont appear by itself in the
    # proof since it isn't hashed with another value
    assert proof2 == [sha3(hash_0 + hash_1)]
    assert root == calculated_root
    assert validate_proof(proof2, root, hash_2)
Exemple #2
0
def test_three():
    hash_0 = b'a' * 32
    hash_1 = b'b' * 32
    hash_2 = b'c' * 32

    leaves = [hash_0, hash_1, hash_2]
    layers = compute_layers(leaves)
    tree = MerkleTreeState(layers)
    root = merkleroot(tree)

    hash_01 = (b'me\xef\x9c\xa9=5\x16\xa4\xd3\x8a\xb7\xd9\x89\xc2\xb5\x00'
               b'\xe2\xfc\x89\xcc\xdc\xf8x\xf9\xc4m\xaa\xf6\xad\r[')
    assert sha3(hash_0 + hash_1) == hash_01
    calculated_root = sha3(hash_2 + hash_01)

    proof0 = compute_merkleproof_for(tree, hash_0)
    proof1 = compute_merkleproof_for(tree, hash_1)
    proof2 = compute_merkleproof_for(tree, hash_2)

    assert proof0 == [hash_1, hash_2]
    assert root == calculated_root
    assert validate_proof(proof0, root, hash_0)

    assert proof1 == [hash_0, hash_2]
    assert root == calculated_root
    assert validate_proof(proof1, root, hash_1)

    # with an odd number of values, the last value wont appear by itself in the
    # proof since it isn't hashed with another value
    assert proof2 == [sha3(hash_0 + hash_1)]
    assert root == calculated_root
    assert validate_proof(proof2, root, hash_2)
def test_merkle_proof_one_lock(tester_chain,
                               tester_nettingchannel_library_address):
    """ computeMerkleRoot and the python implementation must compute the same
    value for a merkle tree with a single lock."""

    auxiliary = deploy_auxiliary_tester(tester_chain,
                                        tester_nettingchannel_library_address)

    amount = 10
    expiration = 77
    secret = sha3(b'test_merkle_proof_one_lock')
    secrethash = sha3(secret)
    lock = Lock(amount, expiration, secrethash)

    layers = compute_layers([lock.lockhash])
    merkletree = MerkleTreeState(layers)

    proof = compute_merkleproof_for(merkletree, lock.lockhash)
    assert len(proof) == 0, 'with only one element the proof is empty'

    smart_contact_root = auxiliary.computeMerkleRoot(
        lock.as_bytes,
        b''.join(proof),
    )

    assert smart_contact_root == merkleroot(merkletree)
def test_merkle_proof_missing_byte(
        tree,
        tester_chain,
        tester_nettingchannel_library_address):
    """ computeMerkleRoot must fail if the proof is missing a byte. """

    auxiliary = deploy_auxiliary_tester(tester_chain, tester_nettingchannel_library_address)

    hashes = [sha3(element) for element in tree]
    layers = compute_layers(hashes)
    merkletree = MerkleTreeState(layers)

    element = hashes[-1]
    proof = compute_merkleproof_for(merkletree, element)

    # for each element of the proof, remove a byte from the start and the end and test it
    for element_to_tamper in range(len(proof)):
        tampered_proof = list(proof)
        tampered_proof[element_to_tamper] = tampered_proof[element_to_tamper][:-1]

        with pytest.raises(TransactionFailed):
            auxiliary.computeMerkleRoot(
                element,
                b''.join(tampered_proof),
            )

        tampered_proof = list(proof)
        tampered_proof[element_to_tamper] = tampered_proof[element_to_tamper][1:]

        with pytest.raises(TransactionFailed):
            auxiliary.computeMerkleRoot(
                element,
                b''.join(tampered_proof),
            )
def test_merkle_proof_missing_byte(tree, tester_chain,
                                   tester_nettingchannel_library_address):
    """ computeMerkleRoot must fail if the proof is missing a byte. """

    auxiliary = deploy_auxiliary_tester(tester_chain,
                                        tester_nettingchannel_library_address)

    hashes = [sha3(element) for element in tree]
    layers = compute_layers(hashes)
    merkletree = MerkleTreeState(layers)

    element = hashes[-1]
    proof = compute_merkleproof_for(merkletree, element)

    # for each element of the proof, remove a byte from the start and the end and test it
    for element_to_tamper in range(len(proof)):
        tampered_proof = list(proof)
        tampered_proof[element_to_tamper] = tampered_proof[
            element_to_tamper][:-1]

        with pytest.raises(TransactionFailed):
            auxiliary.computeMerkleRoot(
                element,
                b''.join(tampered_proof),
            )

        tampered_proof = list(proof)
        tampered_proof[element_to_tamper] = tampered_proof[element_to_tamper][
            1:]

        with pytest.raises(TransactionFailed):
            auxiliary.computeMerkleRoot(
                element,
                b''.join(tampered_proof),
            )
Exemple #6
0
def test_withdraw_fails_with_partial_merkle_proof(tree, tester_channels,
                                                  tester_chain,
                                                  settle_timeout):
    """ withdraw must fail if informed proof is not complete. """
    pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0]

    current_block = tester_chain.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            hashlock=hashlock,
            expiration=expiration,
        ) for hashlock in tree
    ]

    leaves = [sha3(lock.as_bytes) for lock in locks]
    layers = compute_layers(leaves)
    merkle_tree = MerkleTreeState(layers)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2**32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        channel=channel0.identifier,
        locksroot=merkleroot(merkle_tree),
        recipient=privatekey_to_address(pkey1))

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_hash = sha3(direct_transfer.packed().data[:-65])
    nettingchannel.close(
        direct_transfer.nonce,
        direct_transfer.transferred_amount,
        direct_transfer.locksroot,
        direct_transfer_hash,
        direct_transfer.signature,
        sender=pkey1,
    )

    for lock in locks:
        secret = HASHLOCKS_SECRESTS[lock.hashlock]
        lock_encoded = lock.as_bytes
        merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded))

        # withdraw must fail regardless of which part of the proof is removed
        for hash_ in merkle_proof:
            tampered_proof = list(merkle_proof)
            tampered_proof.remove(hash_)

            with pytest.raises(TransactionFailed):
                nettingchannel.withdraw(
                    lock_encoded,
                    b''.join(tampered_proof),
                    secret,
                    sender=pkey1,
                )
Exemple #7
0
def test_two():
    hash_0 = b'a' * 32
    hash_1 = b'b' * 32

    leaves = [hash_0, hash_1]
    layers = compute_layers(leaves)
    tree = MerkleTreeState(layers)
    root = merkleroot(tree)
    proof0 = compute_merkleproof_for(tree, hash_0)
    proof1 = compute_merkleproof_for(tree, hash_1)

    assert proof0 == [hash_1]
    assert root == sha3(hash_0 + hash_1)
    assert validate_proof(proof0, root, hash_0)

    assert proof1 == [hash_0]
    assert root == sha3(hash_0 + hash_1)
    assert validate_proof(proof1, root, hash_1)
def test_two():
    hash_0 = b'a' * 32
    hash_1 = b'b' * 32

    leaves = [hash_0, hash_1]
    layers = compute_layers(leaves)
    tree = MerkleTreeState(layers)
    root = merkleroot(tree)
    proof0 = compute_merkleproof_for(tree, hash_0)
    proof1 = compute_merkleproof_for(tree, hash_1)

    assert proof0 == [hash_1]
    assert root == sha3(hash_0 + hash_1)
    assert validate_proof(proof0, root, hash_0)

    assert proof1 == [hash_0]
    assert root == sha3(hash_0 + hash_1)
    assert validate_proof(proof1, root, hash_1)
Exemple #9
0
def compute_proof_for_lock(end_state: 'NettingChannelEndState',
                           secret: typing.secret,
                           lock: HashTimeLockState) -> UnlockProofState:
    # forcing bytes because ethereum.abi doesn't work with bytearray
    merkle_proof = compute_merkleproof_for(end_state.merkletree, lock.lockhash)

    return UnlockProofState(
        merkle_proof,
        lock.encoded,
        secret,
    )
def test_one():
    hash_0 = b'a' * 32

    leaves = [hash_0]
    layers = compute_layers(leaves)
    tree = MerkleTreeState(layers)
    root = merkleroot(tree)
    proof = compute_merkleproof_for(tree, hash_0)

    assert proof == []
    assert root == hash_0
    assert validate_proof(proof, root, hash_0) is True
Exemple #11
0
def test_one():
    hash_0 = b'a' * 32

    leaves = [hash_0]
    layers = compute_layers(leaves)
    tree = MerkleTreeState(layers)
    root = merkleroot(tree)
    proof = compute_merkleproof_for(tree, hash_0)

    assert proof == []
    assert root == hash_0
    assert validate_proof(proof, root, hash_0) is True
    def compute_proof_for_lock(self, secret, lock, tree=None):
        if tree is None:
            tree = self.merkletree

        # forcing bytes because ethereum.abi doesn't work with bytearray
        lock_encoded = bytes(lock.as_bytes)
        lock_hash = sha3(lock_encoded)

        merkle_proof = compute_merkleproof_for(tree, lock_hash)

        return UnlockProof(
            merkle_proof,
            lock_encoded,
            secret,
        )
def test_many(tree_up_to=10):
    for number_of_leaves in range(1, tree_up_to):  # skipping the empty tree

        leaves = [sha3(str(value)) for value in range(number_of_leaves)]

        layers = compute_layers(leaves)
        tree = MerkleTreeState(layers)
        root = merkleroot(tree)

        for value in leaves:
            proof = compute_merkleproof_for(tree, value)
            assert validate_proof(proof, root, value)

        reversed_tree = MerkleTreeState(compute_layers(reversed(leaves)))
        assert root == merkleroot(reversed_tree)
def test_many(tree_up_to=10):
    for number_of_leaves in range(1, tree_up_to):  # skipping the empty tree

        leaves = [
            sha3(str(value).encode())
            for value in range(number_of_leaves)
        ]

        layers = compute_layers(leaves)
        tree = MerkleTreeState(layers)
        root = merkleroot(tree)

        for value in leaves:
            proof = compute_merkleproof_for(tree, value)
            assert validate_proof(proof, root, value)

        reversed_tree = MerkleTreeState(compute_layers(reversed(leaves)))
        assert root == merkleroot(reversed_tree)
def test_merkle_proof(tree, tester_chain,
                      tester_nettingchannel_library_address):
    """ computeMerkleRoot and the python implementation must compute the same value. """

    auxiliary = deploy_auxiliary_tester(tester_chain,
                                        tester_nettingchannel_library_address)

    hashes = [sha3(element) for element in tree]
    layers = compute_layers(hashes)
    merkletree = MerkleTreeState(layers)

    for element in tree:
        proof = compute_merkleproof_for(merkletree, sha3(element))

        smart_contact_root = auxiliary.computeMerkleRoot(
            element,
            b''.join(proof),
        )

        assert smart_contact_root == merkleroot(merkletree)
def test_merkle_proof(
        tree,
        tester_chain,
        tester_nettingchannel_library_address):
    """ computeMerkleRoot and the python implementation must compute the same value. """

    auxiliary = deploy_auxiliary_tester(tester_chain, tester_nettingchannel_library_address)

    hashes = [sha3(element) for element in tree]
    layers = compute_layers(hashes)
    merkletree = MerkleTreeState(layers)

    for element in tree:
        proof = compute_merkleproof_for(merkletree, sha3(element))

        smart_contact_root = auxiliary.computeMerkleRoot(
            element,
            b''.join(proof),
        )

        assert smart_contact_root == merkleroot(merkletree)
Exemple #17
0
def test_withdraw_tampered_lock_amount(
        tree,
        tester_channels,
        tester_chain,
        tester_token,
        settle_timeout,
):

    """ withdraw must fail if the lock amonut is tampered. """
    pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0]

    current_block = tester_chain.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            secrethash=secrethash,
            expiration=expiration,
        )
        for secrethash in tree
    ]

    leaves = [sha3(lock.as_bytes) for lock in locks]
    layers = compute_layers(leaves)
    merkle_tree = MerkleTreeState(layers)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2 ** 32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        channel=channel0.identifier,
        locksroot=merkleroot(merkle_tree),
        token=tester_token.address,
        recipient=privatekey_to_address(pkey1),
    )

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_hash = sha3(direct_transfer.packed().data[:-65])
    nettingchannel.close(
        direct_transfer.nonce,
        direct_transfer.transferred_amount,
        direct_transfer.locksroot,
        direct_transfer_hash,
        direct_transfer.signature,
        sender=pkey1,
    )

    for lock in locks:
        secret = SECRETHASHES_SECRESTS[lock.secrethash]

        lock_encoded = lock.as_bytes
        merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded))

        tampered_lock = make_lock(
            amount=lock.amount * 100,
            secrethash=lock.secrethash,
            expiration=lock.expiration,
        )
        tampered_lock_encoded = sha3(tampered_lock.as_bytes)

        with pytest.raises(TransactionFailed):
            nettingchannel.withdraw(
                tampered_lock_encoded,
                b''.join(merkle_proof),
                secret,
                sender=pkey1,
            )
Exemple #18
0
def test_withdraw_tampered_merkle_proof(tree, tester_channels, tester_chain, settle_timeout):
    """ withdraw must fail if the proof is tampered. """
    pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0]

    current_block = tester_chain.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            secrethash=secrethash,
            expiration=expiration,
        )
        for secrethash in tree
    ]

    leaves = [sha3(lock.as_bytes) for lock in locks]
    layers = compute_layers(leaves)
    merkle_tree = MerkleTreeState(layers)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2 ** 32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        channel=channel0.identifier,
        locksroot=merkleroot(merkle_tree),
        recipient=privatekey_to_address(pkey1),
    )

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_hash = sha3(direct_transfer.packed().data[:-65])
    nettingchannel.close(
        direct_transfer.nonce,
        direct_transfer.transferred_amount,
        direct_transfer.locksroot,
        direct_transfer_hash,
        direct_transfer.signature,
        sender=pkey1,
    )

    for lock in locks:
        secret = SECRETHASHES_SECRESTS[lock.secrethash]

        lock_encoded = lock.as_bytes
        merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded))

        # withdraw must fail regardless of which part of the proof is tampered
        for pos, hash_ in enumerate(merkle_proof):
            # changing arbitrary bytes from the proof
            tampered_hash = bytearray(hash_)
            tampered_hash[6], tampered_hash[7] = tampered_hash[7], tampered_hash[6]

            tampered_proof = list(merkle_proof)
            tampered_proof[pos] = tampered_hash

            joiner = b''
            with pytest.raises(TransactionFailed):
                nettingchannel.withdraw(
                    lock_encoded,
                    joiner.join(tampered_proof),
                    secret,
                    sender=pkey1,
                )
def test_withdraw_tampered_merkle_proof(tree, tester_channels, tester_chain, settle_timeout):
    """ withdraw must fail if the proof is tampered. """
    pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0]

    current_block = tester_chain.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            hashlock=hashlock,
            expiration=expiration,
        )
        for hashlock in tree
    ]

    leaves = [sha3(lock.as_bytes) for lock in locks]
    layers = compute_layers(leaves)
    merkle_tree = MerkleTreeState(layers)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2 ** 32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        channel=channel0.channel_address,
        locksroot=merkleroot(merkle_tree),
        recipient=privatekey_to_address(pkey1)
    )

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_hash = sha3(direct_transfer.packed().data[:-65])
    nettingchannel.close(
        direct_transfer.nonce,
        direct_transfer.transferred_amount,
        direct_transfer.locksroot,
        direct_transfer_hash,
        direct_transfer.signature,
        sender=pkey1,
    )

    for lock in locks:
        secret = HASHLOCKS_SECRESTS[lock.hashlock]

        lock_encoded = lock.as_bytes
        merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded))

        # withdraw must fail regardless of which part of the proof is tampered
        for pos, hash_ in enumerate(merkle_proof):
            # changing arbitrary bytes from the proof
            tampered_hash = bytearray(hash_)
            tampered_hash[6], tampered_hash[7] = tampered_hash[7], tampered_hash[6]

            tampered_proof = list(merkle_proof)
            tampered_proof[pos] = tampered_hash

            joiner = b''
            with pytest.raises(TransactionFailed):
                nettingchannel.withdraw(
                    lock_encoded,
                    joiner.join(tampered_proof),
                    secret,
                    sender=pkey1,
                )
def test_withdraw_tampered_lock_amount(
        tree,
        tester_channels,
        tester_chain,
        tester_token,
        settle_timeout):

    """ withdraw must fail if the lock amonut is tampered. """
    pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0]

    current_block = tester_chain.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            hashlock=hashlock,
            expiration=expiration,
        )
        for hashlock in tree
    ]

    leaves = [sha3(lock.as_bytes) for lock in locks]
    layers = compute_layers(leaves)
    merkle_tree = MerkleTreeState(layers)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2 ** 32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        channel=channel0.channel_address,
        locksroot=merkleroot(merkle_tree),
        token=tester_token.address,
        recipient=privatekey_to_address(pkey1)
    )

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_hash = sha3(direct_transfer.packed().data[:-65])
    nettingchannel.close(
        direct_transfer.nonce,
        direct_transfer.transferred_amount,
        direct_transfer.locksroot,
        direct_transfer_hash,
        direct_transfer.signature,
        sender=pkey1,
    )

    for lock in locks:
        secret = HASHLOCKS_SECRESTS[lock.hashlock]

        lock_encoded = lock.as_bytes
        merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded))

        tampered_lock = make_lock(
            amount=lock.amount * 100,
            hashlock=lock.hashlock,
            expiration=lock.expiration,
        )
        tampered_lock_encoded = sha3(tampered_lock.as_bytes)

        with pytest.raises(TransactionFailed):
            nettingchannel.withdraw(
                tampered_lock_encoded,
                b''.join(merkle_proof),
                secret,
                sender=pkey1,
            )