def generate_hashes(n, k, header): collision_length = n / (k + 1) bit_len = collision_length + 1 hash_length = (k + 1) * ((collision_length + 7) // 8) indices_per_hash_output = 512 / n num_indices = 2**k digest = blake2b(digest_size=(512 / n) * n / 8, person=zcash_person(n, k)) digest.update(header[:140]) num_bytes = ord(header[140]) if ord(header[140]) < 253 else struct.unpack( '<H', header[141:143])[0] assert num_bytes == bit_len * num_indices / 8, 'Block header does not match Equihash parameters' i = 143 if ord(header[140]) == 253 else 141 soln = get_indices_from_minimal(bytearray(header[i:i + num_bytes]), bit_len) hashes = [] for xi in soln: r = xi % indices_per_hash_output # X_i = H(I||V||x_i) curr_digest = digest.copy() hash_xi(curr_digest, xi / indices_per_hash_output) tmp_hash = curr_digest.digest() hashes.append( expand_array(bytearray(tmp_hash[r * n / 8:(r + 1) * n / 8]), hash_length, collision_length)) return soln, hashes
def testExpandAndCompress(self): out = expand_array(self.compact, len(self.expanded), self.bit_len, self.byte_pad) self.assertEqual(self.expanded, out) out = compress_array(self.expanded, len(self.compact), self.bit_len, self.byte_pad) self.assertEqual(self.compact, out)
def get_indices_from_minimal(minimal, bit_len): eh_index_size = 4 assert (bit_len + 7) / 8 <= eh_index_size len_indices = 8 * eh_index_size * len(minimal) / bit_len byte_pad = eh_index_size - (bit_len + 7) / 8 expanded = expand_array(minimal, len_indices, bit_len, byte_pad) return [ struct.unpack('>I', expanded[i:i + 4])[0] for i in range(0, len_indices, eh_index_size) ]
def gbp_basic(digest, n, k): '''Implementation of Basic Wagner's algorithm for the GBP.''' collision_length = n / (k + 1) hash_length = (k + 1) * ((collision_length + 7) // 8) indices_per_hash_output = 512 / n # 1) Generate first list if DEBUG: print 'Generating first list' X = [] tmp_hash = '' if DEBUG and progressbar: bar = progressbar.ProgressBar() else: bar = lambda x: x for i in bar(range(0, 2**(collision_length + 1))): r = i % indices_per_hash_output if r == 0: # X_i = H(I||V||x_i) curr_digest = digest.copy() hash_xi(curr_digest, i / indices_per_hash_output) tmp_hash = curr_digest.digest() X.append((expand_array(bytearray(tmp_hash[r * n / 8:(r + 1) * n / 8]), hash_length, collision_length), (i, ))) # 3) Repeat step 2 until 2n/(k+1) bits remain for i in range(1, k): if DEBUG: print 'Round %d:' % i # 2a) Sort the list if DEBUG: print '- Sorting list' X.sort(key=itemgetter(0)) if DEBUG and VERBOSE: for Xi in X[-32:]: print '%s %s' % (print_hash(Xi[0]), Xi[1]) if DEBUG: print '- Finding collisions' Xc = [] if DEBUG and progressbar: orig_size = len(X) pbar = progressbar.ProgressBar(max_value=orig_size) while len(X) > 0: # 2b) Find next set of unordered pairs with collisions on first n/(k+1) bits j = 1 while j < len(X): if not has_collision(X[-1][0], X[-1 - j][0], i, collision_length): break j += 1 # 2c) Store tuples (X_i ^ X_j, (i, j)) on the table for l in range(0, j - 1): for m in range(l + 1, j): # Check that there are no duplicate indices in tuples i and j if distinct_indices(X[-1 - l][1], X[-1 - m][1]): if X[-1 - l][1][0] < X[-1 - m][1][0]: concat = X[-1 - l][1] + X[-1 - m][1] else: concat = X[-1 - m][1] + X[-1 - l][1] Xc.append((xor(X[-1 - l][0], X[-1 - m][0]), concat)) # 2d) Drop this set while j > 0: X.pop(-1) j -= 1 if DEBUG and progressbar: pbar.update(orig_size - len(X)) if DEBUG and progressbar: pbar.finish() # 2e) Replace previous list with new list X = Xc # k+1) Find a collision on last 2n(k+1) bits if DEBUG: print 'Final round:' print '- Sorting list' X.sort(key=itemgetter(0)) if DEBUG and VERBOSE: for Xi in X[-32:]: print '%s %s' % (print_hash(Xi[0]), Xi[1]) if DEBUG: print '- Finding collisions' solns = [] if DEBUG and progressbar: orig_size = len(X) pbar = progressbar.ProgressBar(max_value=orig_size, redirect_stdout=True) while len(X) > 0: j = 1 while j < len(X): if not (has_collision(X[-1][0], X[-1 - j][0], k, collision_length) and has_collision(X[-1][0], X[-1 - j][0], k + 1, collision_length)): break j += 1 for l in range(0, j - 1): for m in range(l + 1, j): res = xor(X[-1 - l][0], X[-1 - m][0]) if count_zeroes(res) == 8 * hash_length and distinct_indices( X[-1 - l][1], X[-1 - m][1]): if DEBUG and VERBOSE: print 'Found solution:' print '- %s %s' % (print_hash( X[-1 - l][0]), X[-1 - l][1]) print '- %s %s' % (print_hash( X[-1 - m][0]), X[-1 - m][1]) if X[-1 - l][1][0] < X[-1 - m][1][0]: solns.append(list(X[-1 - l][1] + X[-1 - m][1])) else: solns.append(list(X[-1 - m][1] + X[-1 - l][1])) # 2d) Drop this set while j > 0: X.pop(-1) j -= 1 if DEBUG and progressbar: pbar.update(orig_size - len(X)) if DEBUG and progressbar: pbar.finish() return solns
def gbp_basic(digest, n, k): '''Implementation of Basic Wagner's algorithm for the GBP.''' collision_length = n/(k+1) hash_length = (k+1)*((collision_length+7)//8) indices_per_hash_output = 512/n # 1) Generate first list if DEBUG: print 'Generating first list' X = [] tmp_hash = '' if DEBUG and progressbar: bar = progressbar.ProgressBar() else: bar = lambda x: x for i in bar(range(0, 2**(collision_length+1))): r = i % indices_per_hash_output if r == 0: # X_i = H(I||V||x_i) curr_digest = digest.copy() hash_xi(curr_digest, i/indices_per_hash_output) tmp_hash = curr_digest.digest() X.append(( expand_array(bytearray(tmp_hash[r*n/8:(r+1)*n/8]), hash_length, collision_length), (i,) )) # 3) Repeat step 2 until 2n/(k+1) bits remain for i in range(1, k): if DEBUG: print 'Round %d:' % i # 2a) Sort the list if DEBUG: print '- Sorting list' X.sort(key=itemgetter(0)) if DEBUG and VERBOSE: for Xi in X[-32:]: print '%s %s' % (print_hash(Xi[0]), Xi[1]) if DEBUG: print '- Finding collisions' Xc = [] if DEBUG and progressbar: orig_size = len(X) pbar = progressbar.ProgressBar(max_value=orig_size) while len(X) > 0: # 2b) Find next set of unordered pairs with collisions on first n/(k+1) bits j = 1 while j < len(X): if not has_collision(X[-1][0], X[-1-j][0], i, collision_length): break j += 1 # 2c) Store tuples (X_i ^ X_j, (i, j)) on the table for l in range(0, j-1): for m in range(l+1, j): # Check that there are no duplicate indices in tuples i and j if distinct_indices(X[-1-l][1], X[-1-m][1]): if X[-1-l][1][0] < X[-1-m][1][0]: concat = X[-1-l][1] + X[-1-m][1] else: concat = X[-1-m][1] + X[-1-l][1] Xc.append((xor(X[-1-l][0], X[-1-m][0]), concat)) # 2d) Drop this set while j > 0: X.pop(-1) j -= 1 if DEBUG and progressbar: pbar.update(orig_size - len(X)) if DEBUG and progressbar: pbar.finish() # 2e) Replace previous list with new list X = Xc # k+1) Find a collision on last 2n(k+1) bits if DEBUG: print 'Final round:' print '- Sorting list' X.sort(key=itemgetter(0)) if DEBUG and VERBOSE: for Xi in X[-32:]: print '%s %s' % (print_hash(Xi[0]), Xi[1]) if DEBUG: print '- Finding collisions' solns = [] if DEBUG and progressbar: orig_size = len(X) pbar = progressbar.ProgressBar(max_value=orig_size, redirect_stdout=True) while len(X) > 0: j = 1 while j < len(X): if not (has_collision(X[-1][0], X[-1-j][0], k, collision_length) and has_collision(X[-1][0], X[-1-j][0], k+1, collision_length)): break j += 1 for l in range(0, j-1): for m in range(l+1, j): res = xor(X[-1-l][0], X[-1-m][0]) if count_zeroes(res) == 8*hash_length and distinct_indices(X[-1-l][1], X[-1-m][1]): if DEBUG and VERBOSE: print 'Found solution:' print '- %s %s' % (print_hash(X[-1-l][0]), X[-1-l][1]) print '- %s %s' % (print_hash(X[-1-m][0]), X[-1-m][1]) if X[-1-l][1][0] < X[-1-m][1][0]: solns.append(list(X[-1-l][1] + X[-1-m][1])) else: solns.append(list(X[-1-m][1] + X[-1-l][1])) # 2d) Drop this set while j > 0: X.pop(-1) j -= 1 if DEBUG and progressbar: pbar.update(orig_size - len(X)) if DEBUG and progressbar: pbar.finish() return solns