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_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), )
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, )
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 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
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)
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, )
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, )