def populate_tree(self, flag_bits, hashes): while self.root() is None: # <1> if self.is_leaf(): # <2> flag_bits.pop(0) # <3> self.set_current_node(hashes.pop(0)) # <4> self.up() else: left_hash = self.get_left_node() if left_hash is None: # <5> if flag_bits.pop(0) == 0: # <6> self.set_current_node(hashes.pop(0)) self.up() else: self.left() # <7> elif self.right_exists(): # <8> right_hash = self.get_right_node() if right_hash is None: # <9> self.right() else: # <10> self.set_current_node(merkle_parent(left_hash, right_hash)) self.up() else: # <11> self.set_current_node(merkle_parent(left_hash, left_hash)) self.up() if len(hashes) != 0: # <12> raise RuntimeError('hashes not all consumed {}'.format(len(hashes))) for flag_bit in flag_bits: # <13> if flag_bit != 0: raise RuntimeError('flag bits not all consumed')
def populate_tree(self, flag_bits, hashes): while self.root() is None: if self.is_leaf(): flag_bits.pop(0) self.set_current_node(hashes.pop(0)) self.up() else: left_hash = self.get_left_node() if left_hash is None: if flag_bits.pop(0) == 0: # pre-calculated hash self.set_current_node(hashes.pop(0)) self.up() else: self.left() elif self.right_exists(): right_hash = self.get_right_node() if right_hash is None: self.right() else: self.set_current_node( merkle_parent(left_hash, right_hash)) self.up() else: self.set_current_node(merkle_parent(left_hash, left_hash)) self.up() if len(hashes) != 0: raise RuntimeError(f'hashes not all consumed {len(hashes)}') for flag_bit in flag_bits: if flag_bit != 0: raise RuntimeError('flag bits not all consumed')
def populate_tree(self, flag_bits, hashes): # populate until we have the root while self.root() is None: # if we are a leaf, we know this position's hash if self.is_leaf(): # get the next bit from flag_bits: flag_bits.pop(0) flag_bits.pop(0) # set the current node in the merkle tree to the next hash: hashes.pop(0) self.set_current_node(hashes.pop(0)) # go up a level self.up() # else else: # get the left hash left_hash = self.get_left_node() # Exercise 6.2: get the right hash # if we don't have the left hash if left_hash is None: # if the next flag bit is 0, the next hash is our current node if flag_bits.pop(0) == 0: # set the current node to be the next hash self.set_current_node(hashes.pop(0)) # sub-tree doesn't need calculation, go up self.up() # else else: # go to the left node self.left() # Exercise 6.2: if we don't have the right hash # go to the right node # Exercise 6.2: else # combine the left and right hashes # we've completed this subtree, go up # Exercise 7.2: if the right hash exists elif self.right_exists(): # get the right hash right_hash = self.get_right_node() # if we don't have the right hash if right_hash is None: # go to the right node self.right() # else else: # combine the left and right hashes self.set_current_node( merkle_parent(left_hash, right_hash)) # we've completed this sub-tree, go up self.up() # else else: # combine the left hash twice self.set_current_node(merkle_parent(left_hash, left_hash)) # we've completed this sub-tree, go up self.up() if len(hashes) != 0: raise RuntimeError('hashes not all consumed {}'.format( len(hashes))) for flag_bit in flag_bits: if flag_bit != 0: raise RuntimeError('flag bits not all consumed')
def populate_tree(self, flag_bits, hashes): # populate until we have the root while self.root() is None: # if we are a leaf, we know this position's hash if self.is_leaf(): # get the next bit from flag_bits: flag_bits.pop(0) flag_bit = flag_bits.pop(0) # get the current hash from hashes: hashes.pop(0) current_hash = hashes.pop(0) # set the current node in the merkle tree to the current hash self.set_current_node(current_hash) # if our flag bit is 1, add to the self.proved_txs array if flag_bit == 1: self.proved_txs.append(current_hash[::-1]) # go up a level self.up() # else else: # get the left hash left_hash = self.get_left_node() # if we don't have the left hash if left_hash is None: # if the next flag bit is 0, the next hash is our current node if flag_bits.pop(0) == 0: # set the current node to be the next hash self.set_current_node(hashes.pop(0)) # sub-tree doesn't need calculation, go up self.up() # else else: # go to the left node self.left() elif self.right_exists(): # get the right hash right_hash = self.get_right_node() # if we don't have the right hash if right_hash is None: # go to the right node self.right() # else else: # combine the left and right hashes self.set_current_node( merkle_parent(left_hash, right_hash)) # we've completed this sub-tree, go up self.up() # else else: # combine the left hash twice self.set_current_node(merkle_parent(left_hash, left_hash)) # we've completed this sub-tree, go up self.up() if len(hashes) != 0: raise RuntimeError(f'hashes not all consumed {len(hashes)}') for flag_bit in flag_bits: if flag_bit != 0: raise RuntimeError('flag bits not all consumed')
def verify(self): '''Returns whether this proof is valid''' current = self.tx_hash[::-1] path = merkle_path(self.index, 2**len(self.merkle_proof)) for i, proof_hash in enumerate(self.merkle_proof): if path[i] % 2 == 1: current = merkle_parent(proof_hash, current) else: current = merkle_parent(current, proof_hash) return current[::-1] == self.merkle_root
def populate_tree(self, flag_bits, hashes): # Loop until the root is calculated. while self.root() is None: # For leaf nodes, we are always given the hash. if self.is_leaf(): # We remove the flag bit corresponding to this node. flag_bits.pop(0) # The hash at index 0 is the hash for this node. self.set_current_node(hashes.pop(0)) self.up() else: left_hash = self.get_left_node() # If we don't have the left child value, there are 2 possibilities: 1) This node's value # may be in the hashes list or we need to calculate it. if left_hash is None: # The next flag bit tells us whether we need to calculate this node or it is given to us. # If the bit is a 0, it's hash is given to us. If it's a 1, we need to calculate it. if flag_bits.pop(0) == 0: self.set_current_node(hashes.pop(0)) # Now that we have set the value, we can go up and start working on the other side # of the tree. self.up() # If the bit is not 0, we need to calculate this node's value, so we keep traversing to # the left. else: self.left() # We check that the right node exists. elif self.right_exists(): right_hash = self.get_right_node() # We have the left hash, but not the right. We traverse to the right node to get its value. if right_hash is None: self.right() # We have both left and right hashes, so we calculate the parent to get the current node's value. else: self.set_current_node( merkle_parent(left_hash, right_hash)) self.up() # We have the left node's value, but the right node does not exist. Thus, we calculate # the parent using the left node twice. else: self.set_current_node(merkle_parent(left_hash, left_hash)) self.up() # All hashes must be consumed. if len(hashes) != 0: raise RuntimeError("Not all hashes were consumed.") # All flag bits must be consumed. for flag_bit in flag_bits: if flag_bit != 0: raise RuntimeError("All flag bits must be consumed.")
def test_merkle_parent(self): tx_hash0 = unhexlify( 'c117ea8ec828342f4dfb0ad6bd140e03a50720ece40169ee38bdc15d9eb64cf5') tx_hash1 = unhexlify( 'c131474164b412e3406696da1ee20ab0fc9bf41c8f05fa8ceea7a08d672d7cc5') want = unhexlify( '8b30c5ba100f6f2e5ad1e2a742e5020491240f8eb514fe97c713c31718ad7ecd') self.assertEqual(merkle_parent(tx_hash0, tx_hash1), want)
def verify(self): '''Returns whether this proof is valid''' # current hash starts with self.tx_hash, reversed current = self.tx_hash[::-1] # Get the Merkle Path for the index and 2**len(merkle_proof) path = merkle_path(self.index, 2**len(self.merkle_proof)) # Loop through Merkle Path and proof hashes for proof_hash, index_at_level in zip(self.merkle_proof, path): # if index_at_level is odd, proof_hash goes on left if index_at_level % 2 == 1: # current hash becomes merkle parent of proof_hash and current current = merkle_parent(proof_hash, current) # if index_at_level is even, proof_hash goes on right else: # current hash becomes merkle parent of current and proof_hash current = merkle_parent(current, proof_hash) # if final result reversed is equal to merkle_root, return True return current[::-1] == self.merkle_root
def test_example_13(self): hex_hashes = [ "9745f7173ef14ee4155722d1cbf13304339fd00d900b759c6f9d58579b5765fb", "5573c8ede34936c29cdfdfe743f7f5fdfbd4f54ba0705259e62f39917065cb9b", "82a02ecbb6623b4274dfcab82b336dc017a27136e08521091e443e62582e8f05", "507ccae5ed9b340363a0e6d765af148be9cb1c8766ccc922f83e4ae681658308", "a7a4aec28e7162e1e9ef33dfa30f0bc0526e6cf4b11a576f6c5de58593898330", "bb6267664bd833fd9fc82582853ab144fece26b7a8a5bf328f8a059445b59add", "ea6d7ac1ee77fbacee58fc717b990c4fcccf1b19af43103c090f601677fd8836", "457743861de496c429912558a106b810b0507975a49773228aa788df40730d41", "7688029288efc9e9a0011c960a6ed9e5466581abf3e3a6c26ee317461add619a", "b1ae7f15836cb2286cdd4e2c37bf9bb7da0a2846d06867a429f654b2e7f383c9", "9b74f89fa3f93e71ff2c241f32945d877281a6a50a6bf94adac002980aafe5ab", "b3a92b5b255019bdaf754875633c2de9fec2ab03e6b8ce669d07cb5b18804638", "b5c0b915312b9bdaedd2b86aa2d0f8feffc73a2d37668fd9010179261e25e263", "c9d52c5cb1e557b92c84c52e7c4bfbce859408bedffc8a5560fd6e35e10b8800", "c555bc5fc3bc096df0a0c9532f07640bfb76bfe4fc1ace214b8b228a1297a4c2", "f9dbfafc3af3400954975da24eb325e326960a25b87fffe23eef3e7ed2fb610e", "38faf8c811988dff0a7e6080b1771c97bcc0801c64d9068cffb85e6e7aacaf51", ] tree = MerkleTree(len(hex_hashes)) tree.nodes[5] = [bytes.fromhex(h) for h in hex_hashes] while tree.root() is None: if tree.is_leaf(): tree.up() else: left_hash = tree.get_left_node() if left_hash is None: tree.left() elif tree.right_exists(): right_hash = tree.get_right_node() if right_hash is None: tree.right() else: tree.set_current_node( merkle_parent(left_hash, right_hash)) tree.up() else: tree.set_current_node(merkle_parent(left_hash, left_hash)) tree.up() self.assertEqual( tree.nodes[0][0].hex(), '0a313864f84b284ad13f7f93940d43459808c3c300ed274a90f265802ab10f91')
def verify(self): '''Returns whether this proof is valid''' # current hash starts with self.tx_hash, reversed current = self.tx_hash[::-1] # initialize the current_index to be the index at at base level current_index = self.index # Loop through proof hashes for proof_hash in self.merkle_proof: # if current_index is odd, proof_hash goes on left if current_index % 2 == 1: # current hash becomes merkle parent of proof_hash and current current = merkle_parent(proof_hash, current) # if current_index is even, proof_hash goes on right else: # current hash becomes merkle parent of current and proof_hash current = merkle_parent(current, proof_hash) # update the current_index to be integer divide by 2 current_index //= 2 # if final result reversed is equal to merkle_root, return True return current[::-1] == self.merkle_root
def create_merkle_proof(self, tx_hash): if self.tx_hashes is None: return None elif self.merkle_tree is None: self.calculate_merkle_tree() index = self.merkle_tree[0].index(tx_hash[::-1]) current = self.merkle_tree[0][index] proof_hashes = [] for level, level_index in enumerate( merkle_path(index, len(self.tx_hashes))): if level_index % 2 == 0: partner = self.merkle_tree[level][level_index + 1] current = merkle_parent(current, partner) else: partner = self.merkle_tree[level][level_index - 1] current = merkle_parent(partner, current) proof_hashes.append(partner) # sanity check if current != self.merkle_tree[-1][0]: raise RuntimeError('merkle tree looks invalid') return Proof(self.merkle_root, tx_hash, index, proof_hashes)
def test_example_7(self): hex_hashes = [ '8b30c5ba100f6f2e5ad1e2a742e5020491240f8eb514fe97c713c31718ad7ecd', '7f4e6f9e224e20fda0ae4c44114237f97cd35aca38d83081c9bfd41feb907800', 'ade48f2bbb57318cc79f3a8678febaa827599c509dce5940602e54c7733332e7', '68b3e2ab8182dfd646f13fdf01c335cf32476482d963f5cd94e934e6b3401069', '43e7274e77fbe8e5a42a8fb58f7decdb04d521f319f332d88e6b06f8e6c09e27', ] hashes = [bytes.fromhex(x) for x in hex_hashes] if len(hashes) % 2 == 1: hashes.append(hashes[-1]) parent_level = [] for i in range(0, len(hex_hashes), 2): parent = merkle_parent(hashes[i], hashes[i + 1]) parent_level.append(parent) want = [ '26906cb2caeb03626102f7606ea332784281d5d20e2b4839fbb3dbb37262dbc1', '717a0d17538ff5ad2c020bab38bdcde66e63f3daef88f89095f344918d5d4f96', 'd6c56a5281021a587f5a1e0dd4674bff012c69d960136d96e6d72261d5b696ae', ] self.assertEqual([x.hex() for x in parent_level], want)
def test_example_4(self): hex_hashes = [ 'c117ea8ec828342f4dfb0ad6bd140e03a50720ece40169ee38bdc15d9eb64cf5', 'c131474164b412e3406696da1ee20ab0fc9bf41c8f05fa8ceea7a08d672d7cc5', 'f391da6ecfeed1814efae39e7fcb3838ae0b02c02ae7d0a5848a66947c0727b0', '3d238a92a94532b946c90e19c49351c763696cff3db400485b813aecb8a13181', '10092f2633be5f3ce349bf9ddbde36caa3dd10dfa0ec8106bce23acbff637dae', ] hashes = [bytes.fromhex(x) for x in hex_hashes] if len(hashes) % 2 == 1: hashes.append(hashes[-1]) parent_level = [] for i in range(0, len(hex_hashes), 2): parent = merkle_parent(hashes[i], hashes[i + 1]) parent_level.append(parent) want = [ '8b30c5ba100f6f2e5ad1e2a742e5020491240f8eb514fe97c713c31718ad7ecd', '7f4e6f9e224e20fda0ae4c44114237f97cd35aca38d83081c9bfd41feb907800', '3ecf6115380c77e8aae56660f5634982ee897351ba906a6837d15ebc3a225df0', ] self.assertEqual([x.hex() for x in parent_level], want)