def shuffle_evict(self, leaf): """ Evict using oblivious shuffling etc """ evict_debug = False levels = [None] * len(self.temp_storage) bucket_sizes = Array(self.D + 2, cint) for i in range(self.D + 2): bucket_sizes[i] = regint(0) Program.prog.curr_tape.start_new_basicblock() leaf = self.state.read().reveal() if evict_debug: print_ln('\tEviction leaf: %s', leaf) for i,(entry, depth) in enumerate(zip(self.temp_storage, self.temp_levels)): lca_lev, cbits = self.compute_lca(entry.x[0], leaf, 1 - entry.empty()) level_bits = self.adjust_lca(cbits, depth, 1 - entry.empty()) # last bit indicates stash levels[i] = [sum(level_bits[j]*j for j in range(self.D+2)), level_bits[-1]] if evict_debug: @if_(1 - entry.empty().reveal()) def f(): print_ln('entry (%s, %s) going to level %s', entry.v.reveal(), entry.x[0].reveal(), levels[i][0].reveal()) print_ln('%s ' * len(level_bits), *[b.reveal() for b in level_bits]) if evict_debug: print_ln("") # sort entries+levels by emptiness: buckets already sorted so just perform a # sequence of merges on these and the stash buckets = [[[self.temp_storage[j]] + levels[j] for j in range(self.bucket_size*i,self.bucket_size*(i+1))] for i in range(self.D+1)] stash = [None] * (self.stash_capacity) for i in range(self.stash_capacity): j = i+self.bucket_size*(self.D+1) stash[i] = [self.temp_storage[j]] + levels[j] merged_entries = buckets + [stash] merged_entries = [m for sl in merged_entries for m in sl] me_len = len(merged_entries) while len(merged_entries) & (len(merged_entries)-1) != 0: merged_entries.append(None) # sort taking into account stash etc. (GF(2^n) ONLY atm) permutation.odd_even_merge_sort(merged_entries, lambda a,b: a[0].empty() * (a[-1] - 1 + b[-1]) + 1 - a[-1]) merged_entries = merged_entries[:me_len] # and sort assigned positions by emptiness (non-empty first) empty_bits_and_levels = [[0]*self.bucket_size for i in range(self.D+1)] stash_bits = 0 if evict_debug: print_str('Size bits: ') # convert bucket size bits to bits flagging emptiness for each position for j in range(self.D+1): s = self.size_bits[j] #for b in s: # b.reveal().print_reg('u%d' % j) if self.bucket_size == 4: c = s[0]*s[1] if self.value_type == sgf2n: empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1] + s[2] + c), self.value_type.clear_type(j)] empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1] + s[2]), self.value_type.clear_type(j)] empty_bits_and_levels[j][2] = [1 - self.value_type.bit_type(c + s[2]), self.value_type.clear_type(j)] empty_bits_and_levels[j][3] = [1 - self.value_type.bit_type(s[2]), self.value_type.clear_type(j)] else: empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1] - c + s[2]), self.value_type.clear_type(j)] empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1] + s[2]), self.value_type.clear_type(j)] empty_bits_and_levels[j][2] = [1 - self.value_type.bit_type(c + s[2]), self.value_type.clear_type(j)] empty_bits_and_levels[j][3] = [1 - self.value_type.bit_type(s[2]), self.value_type.clear_type(j)] elif self.bucket_size == 2: if evict_debug: print_str('%s,%s,', s[0].reveal(), s[1].reveal()) empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1]), self.value_type.clear_type(j)] empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1]), self.value_type.clear_type(j)] elif self.bucket_size == 3: c = s[0]*s[1] empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1] - c), self.value_type.clear_type(j)] empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1]), self.value_type.clear_type(j)] empty_bits_and_levels[j][2] = [1 - self.value_type.bit_type(c), self.value_type.clear_type(j)] if evict_debug: print_ln() empty_bits_and_levels = [x for sl in empty_bits_and_levels for x in sl] while len(empty_bits_and_levels) & (len(empty_bits_and_levels)-1) != 0: empty_bits_and_levels.append(None) permutation.odd_even_merge_sort(empty_bits_and_levels, permutation.bitwise_list_comparator) empty_bits_and_levels = [e for e in empty_bits_and_levels if e is not None] # assign levels to empty positions stash_level = self.value_type.clear_type(self.D + 1) if evict_debug: print_ln('Bits and levels: ') for i, entrylev in enumerate(merged_entries): entry = entrylev[0] level = entrylev[1] if i < len(empty_bits_and_levels): new_level = (empty_bits_and_levels[i][1] - level) * entry.empty() + level if evict_debug: print_ln('\t(empty pos %s, entry %s: empty lev %s, entry %s: new %s)', empty_bits_and_levels[i][0].reveal(), entry.empty().reveal(), empty_bits_and_levels[i][1].reveal(), level.reveal(), new_level.reveal()) else: new_level = level + stash_level * entry.empty() if evict_debug: print_ln('\t(entry %s: level %s: new %s)', entry.empty().reveal(), level.reveal(), new_level.reveal()) merged_entries[i] = [entry, new_level] if evict_debug: print_ln() # shuffle entries and levels while len(merged_entries) & (len(merged_entries)-1) != 0: merged_entries.append(None) #self.root.bucket.empty_entry(False)) permutation.rec_shuffle(merged_entries, value_type=self.value_type) merged_entries = [e for e in merged_entries if e is not None] # need to copy entries/levels to memory for re-positioning entries_ram = RAM(self.temp_size, self.entry_type, self.get_array) levels_array = Array(self.temp_size, cint) for i,entrylev in enumerate(merged_entries): if entrylev is not None: entries_ram[i] = entrylev[0] levels_array[i] = entrylev[1].reveal() Program.prog.curr_tape.start_new_basicblock() # reveal shuffled levels @for_range(self.temp_size) def f(i): level = regint(levels_array[i]) sz = regint(bucket_sizes[level]) self.temp_storage[level*self.bucket_size + sz] = entries_ram[i] bucket_sizes[level] += 1 if evict_debug: for i in range(self.D+1): @if_(bucket_sizes[i] != self.bucket_size) def f(): print_str('Sizes: ') for i in range(self.D+2): print_str('%s,', bucket_sizes[i]) print_ln() runtime_error('Incorrect bucket sizes') Program.prog.curr_tape.start_new_basicblock() for i, ram_indices in enumerate(self.bucket_indices_on_path_to(leaf)): for j, ram_index in enumerate(ram_indices): self.buckets[ram_index] = self.temp_storage[i*self.bucket_size + j] for i in range(self.stash_capacity): self.stash.ram[i] = self.temp_storage[i + (self.D+1)*self.bucket_size]
def shuffle_evict(self, leaf): """ Evict using oblivious shuffling etc """ evict_debug = False levels = [None] * len(self.temp_storage) bucket_sizes = Array(self.D + 2, cint) for i in range(self.D + 2): bucket_sizes[i] = regint(0) Program.prog.curr_tape.start_new_basicblock() leaf = self.state.read().reveal() if evict_debug: print_ln('\tEviction leaf: %s', leaf) for i, (entry, depth) in enumerate(zip(self.temp_storage, self.temp_levels)): lca_lev, cbits = self.compute_lca(entry.x[0], leaf, 1 - entry.empty()) level_bits = self.adjust_lca(cbits, depth, 1 - entry.empty()) # last bit indicates stash levels[i] = [ sum(level_bits[j] * j for j in range(self.D + 2)), level_bits[-1] ] if evict_debug: @if_(1 - entry.empty().reveal()) def f(): print_ln('entry (%s, %s) going to level %s', entry.v.reveal(), entry.x[0].reveal(), levels[i][0].reveal()) print_ln('%s ' * len(level_bits), *[b.reveal() for b in level_bits]) if evict_debug: print_ln("") # sort entries+levels by emptiness: buckets already sorted so just perform a # sequence of merges on these and the stash buckets = [[[self.temp_storage[j]] + levels[j] for j in range(self.bucket_size * i, self.bucket_size * (i + 1))] for i in range(self.D + 1)] stash = [None] * (self.stash_capacity) for i in range(self.stash_capacity): j = i + self.bucket_size * (self.D + 1) stash[i] = [self.temp_storage[j]] + levels[j] merged_entries = buckets + [stash] merged_entries = [m for sl in merged_entries for m in sl] me_len = len(merged_entries) while len(merged_entries) & (len(merged_entries) - 1) != 0: merged_entries.append(None) # sort taking into account stash etc. (GF(2^n) ONLY atm) permutation.odd_even_merge_sort( merged_entries, lambda a, b: a[0].empty() * (a[-1] - 1 + b[-1]) + 1 - a[-1]) merged_entries = merged_entries[:me_len] # and sort assigned positions by emptiness (non-empty first) empty_bits_and_levels = [[0] * self.bucket_size for i in range(self.D + 1)] stash_bits = 0 if evict_debug: print_str('Size bits: ') # convert bucket size bits to bits flagging emptiness for each position for j in range(self.D + 1): s = self.size_bits[j] #for b in s: # b.reveal().print_reg('u%d' % j) if self.bucket_size == 4: c = s[0] * s[1] if self.value_type == sgf2n: empty_bits_and_levels[j][0] = [ 1 - self.value_type.bit_type(s[0] + s[1] + s[2] + c), self.value_type.clear_type(j) ] empty_bits_and_levels[j][1] = [ 1 - self.value_type.bit_type(s[1] + s[2]), self.value_type.clear_type(j) ] empty_bits_and_levels[j][2] = [ 1 - self.value_type.bit_type(c + s[2]), self.value_type.clear_type(j) ] empty_bits_and_levels[j][3] = [ 1 - self.value_type.bit_type(s[2]), self.value_type.clear_type(j) ] else: empty_bits_and_levels[j][0] = [ 1 - self.value_type.bit_type(s[0] + s[1] - c + s[2]), self.value_type.clear_type(j) ] empty_bits_and_levels[j][1] = [ 1 - self.value_type.bit_type(s[1] + s[2]), self.value_type.clear_type(j) ] empty_bits_and_levels[j][2] = [ 1 - self.value_type.bit_type(c + s[2]), self.value_type.clear_type(j) ] empty_bits_and_levels[j][3] = [ 1 - self.value_type.bit_type(s[2]), self.value_type.clear_type(j) ] elif self.bucket_size == 2: if evict_debug: print_str('%s,%s,', s[0].reveal(), s[1].reveal()) empty_bits_and_levels[j][0] = [ 1 - self.value_type.bit_type(s[0] + s[1]), self.value_type.clear_type(j) ] empty_bits_and_levels[j][1] = [ 1 - self.value_type.bit_type(s[1]), self.value_type.clear_type(j) ] elif self.bucket_size == 3: c = s[0] * s[1] empty_bits_and_levels[j][0] = [ 1 - self.value_type.bit_type(s[0] + s[1] - c), self.value_type.clear_type(j) ] empty_bits_and_levels[j][1] = [ 1 - self.value_type.bit_type(s[1]), self.value_type.clear_type(j) ] empty_bits_and_levels[j][2] = [ 1 - self.value_type.bit_type(c), self.value_type.clear_type(j) ] if evict_debug: print_ln() empty_bits_and_levels = [x for sl in empty_bits_and_levels for x in sl] while len(empty_bits_and_levels) & (len(empty_bits_and_levels) - 1) != 0: empty_bits_and_levels.append(None) permutation.odd_even_merge_sort(empty_bits_and_levels, permutation.bitwise_list_comparator) empty_bits_and_levels = [ e for e in empty_bits_and_levels if e is not None ] # assign levels to empty positions stash_level = self.value_type.clear_type(self.D + 1) if evict_debug: print_ln('Bits and levels: ') for i, entrylev in enumerate(merged_entries): entry = entrylev[0] level = entrylev[1] if i < len(empty_bits_and_levels): new_level = (empty_bits_and_levels[i][1] - level) * entry.empty() + level if evict_debug: print_ln( '\t(empty pos %s, entry %s: empty lev %s, entry %s: new %s)', empty_bits_and_levels[i][0].reveal(), entry.empty().reveal(), empty_bits_and_levels[i][1].reveal(), level.reveal(), new_level.reveal()) else: new_level = level + stash_level * entry.empty() if evict_debug: print_ln('\t(entry %s: level %s: new %s)', entry.empty().reveal(), level.reveal(), new_level.reveal()) merged_entries[i] = [entry, new_level] if evict_debug: print_ln() # shuffle entries and levels while len(merged_entries) & (len(merged_entries) - 1) != 0: merged_entries.append(None) #self.root.bucket.empty_entry(False)) permutation.rec_shuffle(merged_entries, value_type=self.value_type) merged_entries = [e for e in merged_entries if e is not None] # need to copy entries/levels to memory for re-positioning entries_ram = RAM(self.temp_size, self.entry_type) levels_array = Array(self.temp_size, cint) for i, entrylev in enumerate(merged_entries): if entrylev is not None: entries_ram[i] = entrylev[0] levels_array[i] = entrylev[1].reveal() Program.prog.curr_tape.start_new_basicblock() # reveal shuffled levels @for_range(self.temp_size) def f(i): level = regint(levels_array[i]) sz = regint(bucket_sizes[level]) self.temp_storage[level * self.bucket_size + sz] = entries_ram[i] bucket_sizes[level] += 1 if evict_debug: for i in range(self.D + 1): @if_(bucket_sizes[i] != self.bucket_size) def f(): print_str('Sizes: ') for i in range(self.D + 2): print_str('%s,', bucket_sizes[i]) print_ln() runtime_error('Incorrect bucket sizes') Program.prog.curr_tape.start_new_basicblock() for i, ram_indices in enumerate(self.bucket_indices_on_path_to(leaf)): for j, ram_index in enumerate(ram_indices): self.buckets[ram_index] = self.temp_storage[i * self.bucket_size + j] for i in range(self.stash_capacity): self.stash.ram[i] = self.temp_storage[i + (self.D + 1) * self.bucket_size]
def default_shuffle(values, config, reverse=False, use_iter=True): """Shuffles values in place using default shuffle algorithm.""" if use_iter: shuffle(values, config=config, value_type=sint, reverse=reverse) else: rec_shuffle(values, config=config, value_type=sint, reverse=reverse)