diff --git a/Compiler/__init__.py b/Compiler/__init__.py index b764125d..336a70fd 100644 --- a/Compiler/__init__.py +++ b/Compiler/__init__.py @@ -1,31 +1,37 @@ -import compilerLib, program, instructions, types, library, floatingpoint, mpc_math +import Compiler.compilerLib +import Compiler.program +import Compiler.instructions +import Compiler.types +import Compiler.library +import Compiler.floatingpoint +import Compiler.mpc_math import inspect -from config import * -from compilerLib import run +from Compiler.config import * +from Compiler.compilerLib import run # add all instructions to the program VARS dictionary compilerLib.VARS = {} -instr_classes = [t[1] for t in inspect.getmembers(instructions, inspect.isclass)] +instr_classes = [t[1] for t in inspect.getmembers(Compiler.instructions, inspect.isclass)] -instr_classes += [t[1] for t in inspect.getmembers(types, inspect.isclass)\ - if t[1].__module__ == types.__name__] +instr_classes += [t[1] for t in inspect.getmembers(Compiler.types, inspect.isclass)\ + if t[1].__module__ == Compiler.types.__name__] #instr_classes += [t[1] for t in inspect.getmembers(fixedpoint, inspect.isclass)\ # if t[1].__module__ == fixedpoint.__name__] #instr_classes += [t[1] for t in inspect.getmembers(fixedpoint, inspect.isfunction)\ # if t[1].__module__ == fixedpoint.__name__] -instr_classes += [t[1] for t in inspect.getmembers(library, inspect.isfunction)\ - if t[1].__module__ == library.__name__] +instr_classes += [t[1] for t in inspect.getmembers(Compiler.library, inspect.isfunction)\ + if t[1].__module__ == Compiler.library.__name__] for op in instr_classes: - compilerLib.VARS[op.__name__] = op + Compiler.compilerLib.VARS[op.__name__] = op # add open and input separately due to name conflict -compilerLib.VARS['open'] = instructions.asm_open -compilerLib.VARS['vopen'] = instructions.vasm_open +Compiler.compilerLib.VARS['open'] = Compiler.instructions.asm_open +Compiler.compilerLib.VARS['vopen'] = Compiler.instructions.vasm_open -compilerLib.VARS['comparison'] = comparison -compilerLib.VARS['mpc_math'] = mpc_math -compilerLib.VARS['floatingpoint'] = floatingpoint +Compiler.compilerLib.VARS['comparison'] = Compiler.comparison +Compiler.compilerLib.VARS['mpc_math'] = Compiler.mpc_math +Compiler.compilerLib.VARS['floatingpoint'] = Compiler.floatingpoint diff --git a/Compiler/allocator.py b/Compiler/allocator.py index 96a1e7d4..3fdcae4d 100644 --- a/Compiler/allocator.py +++ b/Compiler/allocator.py @@ -1,634 +1,640 @@ -# (C) 2016 University of Bristol. See License.txt - -import itertools, time -from collections import defaultdict, deque -from Compiler.exceptions import * -from Compiler.config import * -from Compiler.instructions import * -from Compiler.instructions_base import * -from Compiler.util import * -import Compiler.graph -import Compiler.program -import heapq, itertools -import operator -import sys - - -class StraightlineAllocator: - """Allocate variables in a straightline program using n registers. - It is based on the precondition that every register is only defined once.""" - def __init__(self, n): - self.alloc = {} - self.usage = Compiler.program.RegType.create_dict(lambda: 0) - self.defined = {} - self.dealloc = set() - self.n = n - - def alloc_reg(self, reg, free): - base = reg.vectorbase - if base in self.alloc: - # already allocated - return - - reg_type = reg.reg_type - size = base.size - if free[reg_type, size]: - res = free[reg_type, size].pop() - else: - if self.usage[reg_type] < self.n: - res = self.usage[reg_type] - self.usage[reg_type] += size - else: - raise RegisterOverflowError() - self.alloc[base] = res - - if base.vector: - for i,r in enumerate(base.vector): - r.i = self.alloc[base] + i - else: - base.i = self.alloc[base] - - def dealloc_reg(self, reg, inst, free): - self.dealloc.add(reg) - base = reg.vectorbase - - if base.vector and not inst.is_vec(): - for i in base.vector: - if i not in self.dealloc: - # not all vector elements ready for deallocation - return - free[reg.reg_type, base.size].add(self.alloc[base]) - if inst.is_vec() and base.vector: - for i in base.vector: - self.defined[i] = inst - else: - self.defined[reg] = inst - - def process(self, program, alloc_pool): - for k,i in enumerate(reversed(program)): - unused_regs = [] - for j in i.get_def(): - if j.vectorbase in self.alloc: - if j in self.defined: - raise CompilerError("Double write on register %s " \ - "assigned by '%s' in %s" % \ - (j,i,format_trace(i.caller))) - else: - # unused register - self.alloc_reg(j, alloc_pool) - unused_regs.append(j) - if unused_regs and len(unused_regs) == len(i.get_def()): - # only report if all assigned registers are unused - print "Register(s) %s never used, assigned by '%s' in %s" % \ - (unused_regs,i,format_trace(i.caller)) - - for j in i.get_used(): - self.alloc_reg(j, alloc_pool) - for j in i.get_def(): - self.dealloc_reg(j, i, alloc_pool) - - if k % 1000000 == 0 and k > 0: - print "Allocated registers for %d instructions at" % k, time.asctime() - - # print "Successfully allocated registers" - # print "modp usage: %d clear, %d secret" % \ - # (self.usage[Compiler.program.RegType.ClearModp], self.usage[Compiler.program.RegType.SecretModp]) - return self.usage - - -def determine_scope(block, options): - last_def = defaultdict(lambda: -1) - used_from_scope = set() - - def find_in_scope(reg, scope): - if scope is None: - return False - elif reg in scope.defined_registers: - return True - else: - return find_in_scope(reg, scope.scope) - - def read(reg, n): - if last_def[reg] == -1: - if find_in_scope(reg, block.scope): - used_from_scope.add(reg) - reg.can_eliminate = False - else: - print 'Warning: read before write at register', reg - print '\tline %d: %s' % (n, instr) - print '\tinstruction trace: %s' % format_trace(instr.caller, '\t\t') - print '\tregister trace: %s' % format_trace(reg.caller, '\t\t') - if options.stop: - sys.exit(1) - - def write(reg, n): - if last_def[reg] != -1: - print 'Warning: double write at register', reg - print '\tline %d: %s' % (n, instr) - print '\ttrace: %s' % format_trace(instr.caller, '\t\t') - if options.stop: - sys.exit(1) - last_def[reg] = n - - for n,instr in enumerate(block.instructions): - outputs,inputs = instr.get_def(), instr.get_used() - for reg in inputs: - if reg.vector and instr.is_vec(): - for i in reg.vector: - read(i, n) - else: - read(reg, n) - for reg in outputs: - if reg.vector and instr.is_vec(): - for i in reg.vector: - write(i, n) - else: - write(reg, n) - - block.used_from_scope = used_from_scope - block.defined_registers = set(last_def.iterkeys()) - -class Merger: - def __init__(self, block, options): - self.block = block - self.instructions = block.instructions - self.options = options - if options.max_parallel_open: - self.max_parallel_open = int(options.max_parallel_open) - else: - self.max_parallel_open = float('inf') - self.dependency_graph() - - def do_merge(self, merges_iter): - """ Merge an iterable of nodes in G, returning the number of merged - instructions and the index of the merged instruction. """ - instructions = self.instructions - mergecount = 0 - try: - n = next(merges_iter) - except StopIteration: - return mergecount, None - - def expand_vector_args(inst): - new_args = [] - for arg in inst.args: - if inst.is_vec(): - arg.create_vector_elements() - for reg in arg: - new_args.append(reg) - else: - new_args.append(arg) - return new_args - - for i in merges_iter: - if instructions[n].get_size() != instructions[i].get_size(): - # merge as non-vector instruction - instructions[n].args = expand_vector_args(instructions[n]) + \ - expand_vector_args(instructions[i]) - if instructions[n].is_vec(): - instructions[n].size = 1 - else: - instructions[n].args += instructions[i].args - - # join arg_formats if not special iterators - # if not isinstance(instructions[n].arg_format, (itertools.repeat, itertools.cycle)) and \ - # not isinstance(instructions[i].arg_format, (itertools.repeat, itertools.cycle)): - # instructions[n].arg_format += instructions[i].arg_format - instructions[i] = None - self.merge_nodes(n, i) - mergecount += 1 - - return mergecount, n - - def compute_max_depths(self, depth_of): - """ Compute the maximum 'depth' at which every instruction can be placed. - This is the minimum depth of any merge_node succeeding an instruction. - - Similar to DAG shortest paths algorithm. Traverses the graph in reverse - topological order, updating the max depth of each node's predecessors. - """ - G = self.G - merge_nodes_set = self.open_nodes - top_order = Compiler.graph.topological_sort(G) - max_depth_of = [None] * len(G) - max_depth = max(depth_of) - - for i in range(len(max_depth_of)): - if i in merge_nodes_set: - max_depth_of[i] = depth_of[i] - 1 - else: - max_depth_of[i] = max_depth - - for u in reversed(top_order): - for v in G.pred[u]: - if v not in merge_nodes_set: - max_depth_of[v] = min(max_depth_of[u], max_depth_of[v]) - return max_depth_of - - def merge_inputs(self): - merges = defaultdict(list) - remaining_input_nodes = [] - def do_merge(nodes): - if len(nodes) > 1000: - print 'Merging %d inputs...' % len(nodes) - self.do_merge(iter(nodes)) - for n in self.input_nodes: - inst = self.instructions[n] - merge = merges[inst.args[0],inst.__class__] - if len(merge) == 0: - remaining_input_nodes.append(n) - merge.append(n) - if len(merge) >= self.max_parallel_open: - do_merge(merge) - merge[:] = [] - for merge in merges.itervalues(): - if merge: - do_merge(merge) - self.input_nodes = remaining_input_nodes - - def compute_preorder(self, merges, rev_depth_of): - # find flexible nodes that can be on several levels - # and find sources on level 0 - G = self.G - merge_nodes_set = self.open_nodes - depth_of = self.depths - instructions = self.instructions - flex_nodes = defaultdict(dict) - starters = [] - for n in xrange(len(G)): - if n not in merge_nodes_set and \ - depth_of[n] != rev_depth_of[n] and G[n] and G.get_attr(n,'start') == -1: - #print n, depth_of[n], rev_depth_of[n] - flex_nodes[depth_of[n]].setdefault(rev_depth_of[n], set()).add(n) - elif len(G.pred[n]) == 0: - starters.append(n) - if n % 10000000 == 0 and n > 0: - print "Processed %d nodes at" % n, time.asctime() - - inputs = defaultdict(list) - for node in self.input_nodes: - player = self.instructions[node].args[0] - inputs[player].append(node) - first_inputs = [l[0] for l in inputs.itervalues()] - other_inputs = [] - i = 0 - while True: - i += 1 - found = False - for l in inputs.itervalues(): - if i < len(l): - other_inputs.append(l[i]) - found = True - if not found: - break - other_inputs.reverse() - - preorder = [] - # magical preorder for topological search - max_depth = max(merges) - if max_depth > 10000: - print "Computing pre-ordering ..." - for i in xrange(max_depth, 0, -1): - preorder.append(G.get_attr(merges[i], 'stop')) - for j in flex_nodes[i-1].itervalues(): - preorder.extend(j) - preorder.extend(flex_nodes[0].get(i, [])) - preorder.append(merges[i]) - if i % 100000 == 0 and i > 0: - print "Done level %d at" % i, time.asctime() - preorder.extend(other_inputs) - preorder.extend(starters) - preorder.extend(first_inputs) - if max_depth > 10000: - print "Done at", time.asctime() - return preorder - - def compute_continuous_preorder(self, merges, rev_depth_of): - print 'Computing pre-ordering for continuous computation...' - preorder = [] - sources_for = defaultdict(list) - stops_in = defaultdict(list) - startinputs = [] - stopinputs = [] - for source in self.sources: - sources_for[rev_depth_of[source]].append(source) - for merge in merges.itervalues(): - stop = self.G.get_attr(merge, 'stop') - stops_in[rev_depth_of[stop]].append(stop) - for node in self.input_nodes: - stopinputs.append(node) - max_round = max(rev_depth_of) - for i in xrange(max_round, 0, -1): - preorder.extend(reversed(stops_in[i])) - preorder.extend(reversed(sources_for[i])) - # inputs at the beginning - preorder.extend(reversed(stopinputs)) - preorder.extend(reversed(sources_for[0])) - preorder.extend(reversed(startinputs)) - return preorder - - def longest_paths_merge(self, instruction_type=startopen_class, - merge_stopopens=True): - """ Attempt to merge instructions of type instruction_type (which are given in - merge_nodes) using longest paths algorithm. - - Returns the no. of rounds of communication required after merging (assuming 1 round/instruction). - - If merge_stopopens is True, will also merge associated stop_open instructions. - If reorder_between_opens is True, will attempt to place non-opens between start/stop opens. - - Doesn't use networkx. - """ - G = self.G - instructions = self.instructions - merge_nodes = self.open_nodes - depths = self.depths - if instruction_type is not startopen_class and merge_stopopens: - raise CompilerError('Cannot merge stopopens whilst merging %s instructions' % instruction_type) - if not merge_nodes and not self.input_nodes: - return 0 - - # merge opens at same depth - merges = defaultdict(list) - for node in merge_nodes: - merges[depths[node]].append(node) - - # after merging, the first element in merges[i] remains for each depth i, - # all others are removed from instructions and G - last_nodes = [None, None] - for i in sorted(merges): - merge = merges[i] - if len(merge) > 1000: - print 'Merging %d opens in round %d/%d' % (len(merge), i, len(merges)) - # XXXX nodes is two d as we have stripped out gf2n stuff, so b=False to - # index the correct component. This should be fixed later - nodes = defaultdict(lambda: None) - b=False - my_merge = (m for m in merge if instructions[m] is not None) - - if merge_stopopens: - my_stopopen = [G.get_attr(m, 'stop') for m in merge if instructions[m] is not None] - - mc, nodes[0,b] = self.do_merge(iter(my_merge)) - - if merge_stopopens: - mc, nodes[1,b] = self.do_merge(iter(my_stopopen)) - - # add edges to retain order of modp start/stop opens - for j in (0,1): - node2 = nodes[j,True] - nodep = nodes[j,False] - if nodep is not None and node2 is not None: - G.add_edge(nodep, node2) - # add edge to retain order of opens over rounds - if last_nodes[j] is not None: - G.add_edge(last_nodes[j], node2 if nodep is None else nodep) - last_nodes[j] = nodep if node2 is None else node2 - merges[i] = last_nodes[0] - - self.merge_inputs() - - # compute preorder for topological sort - if merge_stopopens and self.options.reorder_between_opens: - if self.options.continuous or not merge_nodes: - rev_depths = self.compute_max_depths(self.real_depths) - preorder = self.compute_continuous_preorder(merges, rev_depths) - else: - rev_depths = self.compute_max_depths(self.depths) - preorder = self.compute_preorder(merges, rev_depths) - else: - preorder = None - - if len(instructions) > 100000: - print "Topological sort ..." - order = Compiler.graph.topological_sort(G, preorder) - instructions[:] = [instructions[i] for i in order if instructions[i] is not None] - if len(instructions) > 100000: - print "Done at", time.asctime() - - return len(merges) - - def dependency_graph(self, merge_class=startopen_class): - """ Create the program dependency graph. """ - block = self.block - options = self.options - open_nodes = set() - self.open_nodes = open_nodes - self.input_nodes = [] - colordict = defaultdict(lambda: 'gray', startopen='red', stopopen='red',\ - ldi='lightblue', ldm='lightblue', stm='blue',\ - mov='yellow', mulm='orange', mulc='orange',\ - triple='green', square='green', bit='green' - ) - - G = Compiler.graph.SparseDiGraph(len(block.instructions)) - self.G = G - - reg_nodes = {} - last_def = defaultdict(lambda: -1) - last_mem_write = [] - last_mem_read = [] - warned_about_mem = [] - last_mem_write_of = defaultdict(list) - last_mem_read_of = defaultdict(list) - last_print_str = None - last = defaultdict(lambda: defaultdict(lambda: None)) - last_open = deque() - - depths = [0] * len(block.instructions) - self.depths = depths - parallel_open = defaultdict(lambda: 0) - next_available_depth = {} - self.sources = [] - self.real_depths = [0] * len(block.instructions) - - def add_edge(i, j): - from_merge = isinstance(block.instructions[i], merge_class) - to_merge = isinstance(block.instructions[j], merge_class) - G.add_edge(i, j) - is_source = G.get_attr(i, 'is_source') and G.get_attr(j, 'is_source') and not from_merge - G.set_attr(j, 'is_source', is_source) - for d in (self.depths, self.real_depths): - if d[j] < d[i]: - d[j] = d[i] - - def read(reg, n): - if last_def[reg] != -1: - add_edge(last_def[reg], n) - - def write(reg, n): - last_def[reg] = n - - def handle_mem_access(addr, reg_type, last_access_this_kind, - last_access_other_kind): - this = last_access_this_kind[addr,reg_type] - other = last_access_other_kind[addr,reg_type] - if this and other: - if this[-1] < other[0]: - del this[:] - this.append(n) - for inst in other: - add_edge(inst, n) - - def mem_access(n, instr, last_access_this_kind, last_access_other_kind): - addr = instr.args[1] - reg_type = instr.args[0].reg_type - if isinstance(addr, int): - for i in range(min(instr.get_size(), 100)): - addr_i = addr + i - handle_mem_access(addr_i, reg_type, last_access_this_kind, - last_access_other_kind) - if not warned_about_mem and (instr.get_size() > 100): - print 'WARNING: Order of memory instructions ' \ - 'not preserved due to long vector, errors possible' - warned_about_mem.append(True) - else: - handle_mem_access(addr, reg_type, last_access_this_kind, - last_access_other_kind) - if not warned_about_mem and not isinstance(instr, DirectMemoryInstruction): - print 'WARNING: Order of memory instructions ' \ - 'not preserved, errors possible' - # hack - warned_about_mem.append(True) - - def keep_order(instr, n, t, arg_index=None): - if arg_index is None: - player = None - else: - player = instr.args[arg_index] - if last[t][player] is not None: - add_edge(last[t][player], n) - last[t][player] = n - - for n,instr in enumerate(block.instructions): - outputs,inputs = instr.get_def(), instr.get_used() - - G.add_node(n, is_source=True) - - # if options.debug: - # col = colordict[instr.__class__.__name__] - # G.add_node(n, color=col, label=str(instr)) - for reg in inputs: - if reg.vector and instr.is_vec(): - for i in reg.vector: - read(i, n) - else: - read(reg, n) - - for reg in outputs: - if reg.vector and instr.is_vec(): - for i in reg.vector: - write(i, n) - else: - write(reg, n) - - if isinstance(instr, merge_class): - open_nodes.add(n) - last_open.append(n) - G.add_node(n, merges=[]) - # the following must happen after adding the edge - self.real_depths[n] += 1 - depth = depths[n] + 1 - if int(options.max_parallel_open): - skipped_depths = set() - while parallel_open[depth] >= int(options.max_parallel_open): - skipped_depths.add(depth) - depth = next_available_depth.get(depth, depth + 1) - for d in skipped_depths: - next_available_depth[d] = depth - parallel_open[depth] += len(instr.args) * instr.get_size() - depths[n] = depth - - if isinstance(instr, stopopen_class): - startopen = last_open.popleft() - add_edge(startopen, n) - G.set_attr(startopen, 'stop', n) - G.set_attr(n, 'start', last_open) - G.add_node(n, merges=[]) - - if isinstance(instr, ReadMemoryInstruction): - if options.preserve_mem_order: - if last_mem_write and last_mem_read and last_mem_write[-1] > last_mem_read[-1]: - last_mem_read[:] = [] - last_mem_read.append(n) - for i in last_mem_write: - add_edge(i, n) - else: - mem_access(n, instr, last_mem_read_of, last_mem_write_of) - elif isinstance(instr, WriteMemoryInstruction): - if options.preserve_mem_order: - if last_mem_write and last_mem_read and last_mem_write[-1] < last_mem_read[-1]: - last_mem_write[:] = [] - last_mem_write.append(n) - for i in last_mem_read: - add_edge(i, n) - else: - mem_access(n, instr, last_mem_write_of, last_mem_read_of) - # keep I/O instructions in order - elif isinstance(instr, IOInstruction): - if last_print_str is not None: - add_edge(last_print_str, n) - last_print_str = n - elif isinstance(instr, StackInstruction): - keep_order(instr, n, StackInstruction) - - if not G.pred[n]: - self.sources.append(n) - - if n % 100000 == 0 and n > 0: - print "Processed dependency of %d/%d instructions at" % \ - (n, len(block.instructions)), time.asctime() - - if len(open_nodes) > 1000: - print "Program has %d %s instructions" % (len(open_nodes), merge_class) - - def merge_nodes(self, i, j): - """ Merge node j into i, removing node j """ - G = self.G - if j in G[i]: - G.remove_edge(i, j) - if i in G[j]: - G.remove_edge(j, i) - G.add_edges_from(zip(itertools.cycle([i]), G[j], [G.weights[(j,k)] for k in G[j]])) - G.add_edges_from(zip(G.pred[j], itertools.cycle([i]), [G.weights[(k,j)] for k in G.pred[j]])) - G.get_attr(i, 'merges').append(j) - G.remove_node(j) - - def eliminate_dead_code(self): - instructions = self.instructions - G = self.G - merge_nodes = self.open_nodes - count = 0 - open_count = 0 - for i,inst in zip(xrange(len(instructions) - 1, -1, -1), reversed(instructions)): - # remove if instruction has result that isn't used - unused_result = not G.degree(i) and len(inst.get_def()) \ - and reduce(operator.and_, (reg.can_eliminate for reg in inst.get_def())) \ - and not isinstance(inst, (DoNotEliminateInstruction)) - stop_node = G.get_attr(i, 'stop') - unused_startopen = stop_node != -1 and instructions[stop_node] is None - if unused_result or unused_startopen: - G.remove_node(i) - merge_nodes.discard(i) - instructions[i] = None - count += 1 - if unused_startopen: - open_count += len(inst.args) - if count > 0: - print 'Eliminated %d dead instructions, among which %d opens' % (count, open_count) - - def print_graph(self, filename): - f = open(filename, 'w') - print >>f, 'digraph G {' - for i in range(self.G.n): - for j in self.G[i]: - print >>f, '"%d: %s" -> "%d: %s";' % \ - (i, self.instructions[i], j, self.instructions[j]) - print >>f, '}' - f.close() - - def print_depth(self, filename): - f = open(filename, 'w') - for i in range(self.G.n): - print >>f, '%d: %s' % (self.depths[i], self.instructions[i]) - f.close() +from __future__ import print_function +# (C) 2016 University of Bristol. See License.txt + +from builtins import next +from builtins import zip +from builtins import range +from builtins import object +import itertools, time +from collections import defaultdict, deque +from Compiler.exceptions import * +from Compiler.config import * +from Compiler.instructions import * +from Compiler.instructions_base import * +from Compiler.util import * +import Compiler.graph +import Compiler.program +import heapq, itertools +import operator +import sys +from functools import reduce + + +class StraightlineAllocator(object): + """Allocate variables in a straightline program using n registers. + It is based on the precondition that every register is only defined once.""" + def __init__(self, n): + self.alloc = {} + self.usage = Compiler.program.RegType.create_dict(lambda: 0) + self.defined = {} + self.dealloc = set() + self.n = n + + def alloc_reg(self, reg, free): + base = reg.vectorbase + if base in self.alloc: + # already allocated + return + + reg_type = reg.reg_type + size = base.size + if free[reg_type, size]: + res = free[reg_type, size].pop() + else: + if self.usage[reg_type] < self.n: + res = self.usage[reg_type] + self.usage[reg_type] += size + else: + raise RegisterOverflowError() + self.alloc[base] = res + + if base.vector: + for i,r in enumerate(base.vector): + r.i = self.alloc[base] + i + else: + base.i = self.alloc[base] + + def dealloc_reg(self, reg, inst, free): + self.dealloc.add(reg) + base = reg.vectorbase + + if base.vector and not inst.is_vec(): + for i in base.vector: + if i not in self.dealloc: + # not all vector elements ready for deallocation + return + free[reg.reg_type, base.size].add(self.alloc[base]) + if inst.is_vec() and base.vector: + for i in base.vector: + self.defined[i] = inst + else: + self.defined[reg] = inst + + def process(self, program, alloc_pool): + for k,i in enumerate(reversed(program)): + unused_regs = [] + for j in i.get_def(): + if j.vectorbase in self.alloc: + if j in self.defined: + raise CompilerError("Double write on register %s " \ + "assigned by '%s' in %s" % \ + (j,i,format_trace(i.caller))) + else: + # unused register + self.alloc_reg(j, alloc_pool) + unused_regs.append(j) + if unused_regs and len(unused_regs) == len(i.get_def()): + # only report if all assigned registers are unused + print("Register(s) %s never used, assigned by '%s' in %s" % \ + (unused_regs,i,format_trace(i.caller))) + + for j in i.get_used(): + self.alloc_reg(j, alloc_pool) + for j in i.get_def(): + self.dealloc_reg(j, i, alloc_pool) + + if k % 1000000 == 0 and k > 0: + print("Allocated registers for %d instructions at" % k, time.asctime()) + + # print "Successfully allocated registers" + # print "modp usage: %d clear, %d secret" % \ + # (self.usage[Compiler.program.RegType.ClearModp], self.usage[Compiler.program.RegType.SecretModp]) + return self.usage + + +def determine_scope(block, options): + last_def = defaultdict(lambda: -1) + used_from_scope = set() + + def find_in_scope(reg, scope): + if scope is None: + return False + elif reg in scope.defined_registers: + return True + else: + return find_in_scope(reg, scope.scope) + + def read(reg, n): + if last_def[reg] == -1: + if find_in_scope(reg, block.scope): + used_from_scope.add(reg) + reg.can_eliminate = False + else: + print('Warning: read before write at register', reg) + print('\tline %d: %s' % (n, instr)) + print('\tinstruction trace: %s' % format_trace(instr.caller, '\t\t')) + print('\tregister trace: %s' % format_trace(reg.caller, '\t\t')) + if options.stop: + sys.exit(1) + + def write(reg, n): + if last_def[reg] != -1: + print('Warning: double write at register', reg) + print('\tline %d: %s' % (n, instr)) + print('\ttrace: %s' % format_trace(instr.caller, '\t\t')) + if options.stop: + sys.exit(1) + last_def[reg] = n + + for n,instr in enumerate(block.instructions): + outputs,inputs = instr.get_def(), instr.get_used() + for reg in inputs: + if reg.vector and instr.is_vec(): + for i in reg.vector: + read(i, n) + else: + read(reg, n) + for reg in outputs: + if reg.vector and instr.is_vec(): + for i in reg.vector: + write(i, n) + else: + write(reg, n) + + block.used_from_scope = used_from_scope + block.defined_registers = set(last_def.keys()) + +class Merger(object): + def __init__(self, block, options): + self.block = block + self.instructions = block.instructions + self.options = options + if options.max_parallel_open: + self.max_parallel_open = int(options.max_parallel_open) + else: + self.max_parallel_open = float('inf') + self.dependency_graph() + + def do_merge(self, merges_iter): + """ Merge an iterable of nodes in G, returning the number of merged + instructions and the index of the merged instruction. """ + instructions = self.instructions + mergecount = 0 + try: + n = next(merges_iter) + except StopIteration: + return mergecount, None + + def expand_vector_args(inst): + new_args = [] + for arg in inst.args: + if inst.is_vec(): + arg.create_vector_elements() + for reg in arg: + new_args.append(reg) + else: + new_args.append(arg) + return new_args + + for i in merges_iter: + if instructions[n].get_size() != instructions[i].get_size(): + # merge as non-vector instruction + instructions[n].args = expand_vector_args(instructions[n]) + \ + expand_vector_args(instructions[i]) + if instructions[n].is_vec(): + instructions[n].size = 1 + else: + instructions[n].args += instructions[i].args + + # join arg_formats if not special iterators + # if not isinstance(instructions[n].arg_format, (itertools.repeat, itertools.cycle)) and \ + # not isinstance(instructions[i].arg_format, (itertools.repeat, itertools.cycle)): + # instructions[n].arg_format += instructions[i].arg_format + instructions[i] = None + self.merge_nodes(n, i) + mergecount += 1 + + return mergecount, n + + def compute_max_depths(self, depth_of): + """ Compute the maximum 'depth' at which every instruction can be placed. + This is the minimum depth of any merge_node succeeding an instruction. + + Similar to DAG shortest paths algorithm. Traverses the graph in reverse + topological order, updating the max depth of each node's predecessors. + """ + G = self.G + merge_nodes_set = self.open_nodes + top_order = Compiler.graph.topological_sort(G) + max_depth_of = [None] * len(G) + max_depth = max(depth_of) + + for i in range(len(max_depth_of)): + if i in merge_nodes_set: + max_depth_of[i] = depth_of[i] - 1 + else: + max_depth_of[i] = max_depth + + for u in reversed(top_order): + for v in G.pred[u]: + if v not in merge_nodes_set: + max_depth_of[v] = min(max_depth_of[u], max_depth_of[v]) + return max_depth_of + + def merge_inputs(self): + merges = defaultdict(list) + remaining_input_nodes = [] + def do_merge(nodes): + if len(nodes) > 1000: + print('Merging %d inputs...' % len(nodes)) + self.do_merge(iter(nodes)) + for n in self.input_nodes: + inst = self.instructions[n] + merge = merges[inst.args[0],inst.__class__] + if len(merge) == 0: + remaining_input_nodes.append(n) + merge.append(n) + if len(merge) >= self.max_parallel_open: + do_merge(merge) + merge[:] = [] + for merge in merges.values(): + if merge: + do_merge(merge) + self.input_nodes = remaining_input_nodes + + def compute_preorder(self, merges, rev_depth_of): + # find flexible nodes that can be on several levels + # and find sources on level 0 + G = self.G + merge_nodes_set = self.open_nodes + depth_of = self.depths + instructions = self.instructions + flex_nodes = defaultdict(dict) + starters = [] + for n in range(len(G)): + if n not in merge_nodes_set and \ + depth_of[n] != rev_depth_of[n] and G[n] and G.get_attr(n,'start') == -1: + #print n, depth_of[n], rev_depth_of[n] + flex_nodes[depth_of[n]].setdefault(rev_depth_of[n], set()).add(n) + elif len(G.pred[n]) == 0: + starters.append(n) + if n % 10000000 == 0 and n > 0: + print("Processed %d nodes at" % n, time.asctime()) + + inputs = defaultdict(list) + for node in self.input_nodes: + player = self.instructions[node].args[0] + inputs[player].append(node) + first_inputs = [l[0] for l in inputs.values()] + other_inputs = [] + i = 0 + while True: + i += 1 + found = False + for l in inputs.values(): + if i < len(l): + other_inputs.append(l[i]) + found = True + if not found: + break + other_inputs.reverse() + + preorder = [] + # magical preorder for topological search + max_depth = max(merges) + if max_depth > 10000: + print("Computing pre-ordering ...") + for i in range(max_depth, 0, -1): + preorder.append(G.get_attr(merges[i], 'stop')) + for j in flex_nodes[i-1].values(): + preorder.extend(j) + preorder.extend(flex_nodes[0].get(i, [])) + preorder.append(merges[i]) + if i % 100000 == 0 and i > 0: + print("Done level %d at" % i, time.asctime()) + preorder.extend(other_inputs) + preorder.extend(starters) + preorder.extend(first_inputs) + if max_depth > 10000: + print("Done at", time.asctime()) + return preorder + + def compute_continuous_preorder(self, merges, rev_depth_of): + print('Computing pre-ordering for continuous computation...') + preorder = [] + sources_for = defaultdict(list) + stops_in = defaultdict(list) + startinputs = [] + stopinputs = [] + for source in self.sources: + sources_for[rev_depth_of[source]].append(source) + for merge in merges.values(): + stop = self.G.get_attr(merge, 'stop') + stops_in[rev_depth_of[stop]].append(stop) + for node in self.input_nodes: + stopinputs.append(node) + max_round = max(rev_depth_of) + for i in range(max_round, 0, -1): + preorder.extend(reversed(stops_in[i])) + preorder.extend(reversed(sources_for[i])) + # inputs at the beginning + preorder.extend(reversed(stopinputs)) + preorder.extend(reversed(sources_for[0])) + preorder.extend(reversed(startinputs)) + return preorder + + def longest_paths_merge(self, instruction_type=startopen_class, + merge_stopopens=True): + """ Attempt to merge instructions of type instruction_type (which are given in + merge_nodes) using longest paths algorithm. + + Returns the no. of rounds of communication required after merging (assuming 1 round/instruction). + + If merge_stopopens is True, will also merge associated stop_open instructions. + If reorder_between_opens is True, will attempt to place non-opens between start/stop opens. + + Doesn't use networkx. + """ + G = self.G + instructions = self.instructions + merge_nodes = self.open_nodes + depths = self.depths + if instruction_type is not startopen_class and merge_stopopens: + raise CompilerError('Cannot merge stopopens whilst merging %s instructions' % instruction_type) + if not merge_nodes and not self.input_nodes: + return 0 + + # merge opens at same depth + merges = defaultdict(list) + for node in merge_nodes: + merges[depths[node]].append(node) + + # after merging, the first element in merges[i] remains for each depth i, + # all others are removed from instructions and G + last_nodes = [None, None] + for i in sorted(merges): + merge = merges[i] + if len(merge) > 1000: + print('Merging %d opens in round %d/%d' % (len(merge), i, len(merges))) + # XXXX nodes is two d as we have stripped out gf2n stuff, so b=False to + # index the correct component. This should be fixed later + nodes = defaultdict(lambda: None) + b=False + my_merge = (m for m in merge if instructions[m] is not None) + + if merge_stopopens: + my_stopopen = [G.get_attr(m, 'stop') for m in merge if instructions[m] is not None] + + mc, nodes[0,b] = self.do_merge(iter(my_merge)) + + if merge_stopopens: + mc, nodes[1,b] = self.do_merge(iter(my_stopopen)) + + # add edges to retain order of modp start/stop opens + for j in (0,1): + node2 = nodes[j,True] + nodep = nodes[j,False] + if nodep is not None and node2 is not None: + G.add_edge(nodep, node2) + # add edge to retain order of opens over rounds + if last_nodes[j] is not None: + G.add_edge(last_nodes[j], node2 if nodep is None else nodep) + last_nodes[j] = nodep if node2 is None else node2 + merges[i] = last_nodes[0] + + self.merge_inputs() + + # compute preorder for topological sort + if merge_stopopens and self.options.reorder_between_opens: + if self.options.continuous or not merge_nodes: + rev_depths = self.compute_max_depths(self.real_depths) + preorder = self.compute_continuous_preorder(merges, rev_depths) + else: + rev_depths = self.compute_max_depths(self.depths) + preorder = self.compute_preorder(merges, rev_depths) + else: + preorder = None + + if len(instructions) > 100000: + print("Topological sort ...") + order = Compiler.graph.topological_sort(G, preorder) + instructions[:] = [instructions[i] for i in order if instructions[i] is not None] + if len(instructions) > 100000: + print("Done at", time.asctime()) + + return len(merges) + + def dependency_graph(self, merge_class=startopen_class): + """ Create the program dependency graph. """ + block = self.block + options = self.options + open_nodes = set() + self.open_nodes = open_nodes + self.input_nodes = [] + colordict = defaultdict(lambda: 'gray', startopen='red', stopopen='red',\ + ldi='lightblue', ldm='lightblue', stm='blue',\ + mov='yellow', mulm='orange', mulc='orange',\ + triple='green', square='green', bit='green' + ) + + G = Compiler.graph.SparseDiGraph(len(block.instructions)) + self.G = G + + reg_nodes = {} + last_def = defaultdict(lambda: -1) + last_mem_write = [] + last_mem_read = [] + warned_about_mem = [] + last_mem_write_of = defaultdict(list) + last_mem_read_of = defaultdict(list) + last_print_str = None + last = defaultdict(lambda: defaultdict(lambda: None)) + last_open = deque() + + depths = [0] * len(block.instructions) + self.depths = depths + parallel_open = defaultdict(lambda: 0) + next_available_depth = {} + self.sources = [] + self.real_depths = [0] * len(block.instructions) + + def add_edge(i, j): + from_merge = isinstance(block.instructions[i], merge_class) + to_merge = isinstance(block.instructions[j], merge_class) + G.add_edge(i, j) + is_source = G.get_attr(i, 'is_source') and G.get_attr(j, 'is_source') and not from_merge + G.set_attr(j, 'is_source', is_source) + for d in (self.depths, self.real_depths): + if d[j] < d[i]: + d[j] = d[i] + + def read(reg, n): + if last_def[reg] != -1: + add_edge(last_def[reg], n) + + def write(reg, n): + last_def[reg] = n + + def handle_mem_access(addr, reg_type, last_access_this_kind, + last_access_other_kind): + this = last_access_this_kind[addr,reg_type] + other = last_access_other_kind[addr,reg_type] + if this and other: + if this[-1] < other[0]: + del this[:] + this.append(n) + for inst in other: + add_edge(inst, n) + + def mem_access(n, instr, last_access_this_kind, last_access_other_kind): + addr = instr.args[1] + reg_type = instr.args[0].reg_type + if isinstance(addr, int): + for i in range(min(instr.get_size(), 100)): + addr_i = addr + i + handle_mem_access(addr_i, reg_type, last_access_this_kind, + last_access_other_kind) + if not warned_about_mem and (instr.get_size() > 100): + print('WARNING: Order of memory instructions ' \ + 'not preserved due to long vector, errors possible') + warned_about_mem.append(True) + else: + handle_mem_access(addr, reg_type, last_access_this_kind, + last_access_other_kind) + if not warned_about_mem and not isinstance(instr, DirectMemoryInstruction): + print('WARNING: Order of memory instructions ' \ + 'not preserved, errors possible') + # hack + warned_about_mem.append(True) + + def keep_order(instr, n, t, arg_index=None): + if arg_index is None: + player = None + else: + player = instr.args[arg_index] + if last[t][player] is not None: + add_edge(last[t][player], n) + last[t][player] = n + + for n,instr in enumerate(block.instructions): + outputs,inputs = instr.get_def(), instr.get_used() + + G.add_node(n, is_source=True) + + # if options.debug: + # col = colordict[instr.__class__.__name__] + # G.add_node(n, color=col, label=str(instr)) + for reg in inputs: + if reg.vector and instr.is_vec(): + for i in reg.vector: + read(i, n) + else: + read(reg, n) + + for reg in outputs: + if reg.vector and instr.is_vec(): + for i in reg.vector: + write(i, n) + else: + write(reg, n) + + if isinstance(instr, merge_class): + open_nodes.add(n) + last_open.append(n) + G.add_node(n, merges=[]) + # the following must happen after adding the edge + self.real_depths[n] += 1 + depth = depths[n] + 1 + if int(options.max_parallel_open): + skipped_depths = set() + while parallel_open[depth] >= int(options.max_parallel_open): + skipped_depths.add(depth) + depth = next_available_depth.get(depth, depth + 1) + for d in skipped_depths: + next_available_depth[d] = depth + parallel_open[depth] += len(instr.args) * instr.get_size() + depths[n] = depth + + if isinstance(instr, stopopen_class): + startopen = last_open.popleft() + add_edge(startopen, n) + G.set_attr(startopen, 'stop', n) + G.set_attr(n, 'start', last_open) + G.add_node(n, merges=[]) + + if isinstance(instr, ReadMemoryInstruction): + if options.preserve_mem_order: + if last_mem_write and last_mem_read and last_mem_write[-1] > last_mem_read[-1]: + last_mem_read[:] = [] + last_mem_read.append(n) + for i in last_mem_write: + add_edge(i, n) + else: + mem_access(n, instr, last_mem_read_of, last_mem_write_of) + elif isinstance(instr, WriteMemoryInstruction): + if options.preserve_mem_order: + if last_mem_write and last_mem_read and last_mem_write[-1] < last_mem_read[-1]: + last_mem_write[:] = [] + last_mem_write.append(n) + for i in last_mem_read: + add_edge(i, n) + else: + mem_access(n, instr, last_mem_write_of, last_mem_read_of) + # keep I/O instructions in order + elif isinstance(instr, IOInstruction): + if last_print_str is not None: + add_edge(last_print_str, n) + last_print_str = n + elif isinstance(instr, StackInstruction): + keep_order(instr, n, StackInstruction) + + if not G.pred[n]: + self.sources.append(n) + + if n % 100000 == 0 and n > 0: + print("Processed dependency of %d/%d instructions at" % \ + (n, len(block.instructions)), time.asctime()) + + if len(open_nodes) > 1000: + print("Program has %d %s instructions" % (len(open_nodes), merge_class)) + + def merge_nodes(self, i, j): + """ Merge node j into i, removing node j """ + G = self.G + if j in G[i]: + G.remove_edge(i, j) + if i in G[j]: + G.remove_edge(j, i) + G.add_edges_from(list(zip(itertools.cycle([i]), G[j], [G.weights[(j,k)] for k in G[j]]))) + G.add_edges_from(list(zip(G.pred[j], itertools.cycle([i]), [G.weights[(k,j)] for k in G.pred[j]]))) + G.get_attr(i, 'merges').append(j) + G.remove_node(j) + + def eliminate_dead_code(self): + instructions = self.instructions + G = self.G + merge_nodes = self.open_nodes + count = 0 + open_count = 0 + for i,inst in zip(range(len(instructions) - 1, -1, -1), reversed(instructions)): + # remove if instruction has result that isn't used + unused_result = not G.degree(i) and len(inst.get_def()) \ + and reduce(operator.and_, (reg.can_eliminate for reg in inst.get_def())) \ + and not isinstance(inst, (DoNotEliminateInstruction)) + stop_node = G.get_attr(i, 'stop') + unused_startopen = stop_node != -1 and instructions[stop_node] is None + if unused_result or unused_startopen: + G.remove_node(i) + merge_nodes.discard(i) + instructions[i] = None + count += 1 + if unused_startopen: + open_count += len(inst.args) + if count > 0: + print('Eliminated %d dead instructions, among which %d opens' % (count, open_count)) + + def print_graph(self, filename): + f = open(filename, 'w') + print('digraph G {', file=f) + for i in range(self.G.n): + for j in self.G[i]: + print('"%d: %s" -> "%d: %s";' % \ + (i, self.instructions[i], j, self.instructions[j]), file=f) + print('}', file=f) + f.close() + + def print_depth(self, filename): + f = open(filename, 'w') + for i in range(self.G.n): + print('%d: %s' % (self.depths[i], self.instructions[i]), file=f) + f.close() diff --git a/Compiler/circuit_oram.py b/Compiler/circuit_oram.py index a87ece00..7b54edd9 100644 --- a/Compiler/circuit_oram.py +++ b/Compiler/circuit_oram.py @@ -1,4 +1,12 @@ +from __future__ import print_function +from __future__ import division +from builtins import map +from builtins import next +from builtins import zip +from builtins import str +from builtins import range +from past.utils import old_div from Compiler.path_oram import * from Compiler.util import bit_compose from Compiler import floatingpoint @@ -39,7 +47,7 @@ def find_deeper(a, b, path, start, length, compute_level=True): def find_deepest(paths, search_path, start, length, compute_level=True): if len(paths) == 1: return None, paths[0], 1 - l = len(paths) / 2 + l = old_div(len(paths), 2) _, a, a_index = find_deepest(paths[:l], search_path, start, length, False) _, b, b_index = find_deepest(paths[l:], search_path, start, length, False) level, winner = find_deeper(a, b, search_path, start, length, compute_level) @@ -58,7 +66,7 @@ def greater_unary(a, b): if len(a) == 1: return a[0], b[0] else: - l = len(a) / 2 + l = old_div(len(a), 2) return gu_step(greater_unary(a[l:], b[l:]), greater_unary(a[:l], b[:l])) def comp_step(high, low): @@ -76,7 +84,7 @@ def comp_binary(a, b): if len(a) == 1: return a[0], b[0] else: - l = len(a) / 2 + l = old_div(len(a), 2) return comp_step(comp_binary(a[l:], b[l:]), comp_binary(a[:l], b[:l])) def unary_to_binary(l): @@ -90,8 +98,8 @@ def __init__(self, size, value_type=sgf2n, value_length=1, entry_size=None, \ self.D = log2(size) self.logD = log2(self.D) self.L = self.D + 1 - print 'create oram of size %d with depth %d and %d buckets' \ - % (size, self.D, self.n_buckets()) + print('create oram of size %d with depth %d and %d buckets' \ + % (size, self.D, self.n_buckets())) self.value_type = value_type if entry_size is not None: self.value_length = len(tuplify(entry_size)) diff --git a/Compiler/comparison.py b/Compiler/comparison.py index 58ea5811..e6827bcb 100644 --- a/Compiler/comparison.py +++ b/Compiler/comparison.py @@ -13,11 +13,14 @@ [1] https://www1.cs.fau.de/filepool/publications/octavian_securescm/smcint-scn10.pdf [2] https://www1.cs.fau.de/filepool/publications/octavian_securescm/SecureSCM-D.9.2.pdf """ +from __future__ import division # Use constant rounds protocols instead of log rounds +from builtins import range +from past.utils import old_div const_rounds = False -import instructions_base +import Compiler.instructions_base def set_variant(options): """ Set flags based on the command-line option provided """ @@ -34,7 +37,7 @@ def ld2i(c, n): """ Load immediate 2^n into clear GF(p) register c """ t1 = program.curr_block.new_reg('c') ldi(t1, 2 ** (n % 30)) - for i in range(n / 30): + for i in range(old_div(n, 30)): t2 = program.curr_block.new_reg('c') mulci(t2, t1, 2 ** 30) t1 = t2 @@ -44,11 +47,11 @@ def ld2i(c, n): def divide_by_two(res, x): """ Faster clear division by two using a cached value of 2^-1 mod p """ - from program import Program - import types + from Compiler.program import Program + import Compiler.types block = Program.prog.curr_block if len(inverse_of_two) == 0 or block not in inverse_of_two: - inverse_of_two[block] = types.cint(1) / 2 + inverse_of_two[block] = old_div(Compiler.types.cint(1), 2) mulc(res, x, inverse_of_two[block]) def LTZ(s, a, k, kappa): @@ -93,12 +96,12 @@ def TruncRoundNearest(a, k, m, kappa): k: bit length of m m: compile-time integer """ - from types import sint, cint - from library import reveal, load_int_to_secret + from Compiler.types import sint, cint + from Compiler.library import reveal, load_int_to_secret if m == 1: lsb = sint() Mod2(lsb, a, k, kappa, False) - return (a + lsb) / 2 + return old_div((a + lsb), 2) r_dprime = sint() r_prime = sint() r = [sint() for i in range(m)] @@ -110,13 +113,13 @@ def TruncRoundNearest(a, k, m, kappa): BitLTC1(u, c_prime, r[:-1], kappa) else: BitLTL(u, c_prime, r[:-1], kappa) - bit = ((c - c_prime) / (cint(1) << (m - 1))) % 2 + bit = (old_div((c - c_prime), (cint(1) << (m - 1)))) % 2 xor = bit + u - 2 * bit * u prod = xor * r[-1] # u_prime = xor * u + (1 - xor) * r[-1] u_prime = bit * u + u - 2 * bit * u + r[-1] - prod a_prime = (c % (cint(1) << m)) - r_prime + (cint(1) << m) * u_prime - d = (a - a_prime) / (cint(1) << m) + d = old_div((a - a_prime), (cint(1) << m)) rounding = xor + r[-1] - 2 * prod return d + rounding @@ -203,7 +206,7 @@ def BitLTC1(u, a, b, kappa): """ k = len(b) p = [program.curr_block.new_reg('s') for i in range(k)] - if instructions_base.get_global_vector_size() == 1: + if Compiler.instructions_base.get_global_vector_size() == 1: b_vec = program.curr_block.new_reg('s', size=k) for i in range(k): movs(b_vec[i], b[i]) @@ -226,7 +229,7 @@ def BitLTC1(u, a, b, kappa): subc(c[0][i], c[1][i-1], a_bits[i-1]) divide_by_two(c[1][i], c[0][i]) modci(a_bits[i], c[1][i], 2) - if instructions_base.get_global_vector_size() == 1: + if Compiler.instructions_base.get_global_vector_size() == 1: vmulci(k, c[2], a_bits, 2) vmulm(k, t[0], b_vec, c[2]) vaddm(k, t[1], b_vec, a_bits) @@ -279,12 +282,12 @@ def CarryOutAux(d, a, kappa): if k > 1 and k % 2 == 1: a.append(None) k += 1 - u = [None]*(k/2) + u = [None]*(old_div(k,2)) a = a[::-1] if k > 1: - for i in range(k/2): - u[i] = carry(a[2*i+1], a[2*i], i != k/2-1) - CarryOutAux(d, u[:k/2][::-1], kappa) + for i in range(old_div(k,2)): + u[i] = carry(a[2*i+1], a[2*i], i != old_div(k,2)-1) + CarryOutAux(d, u[:old_div(k,2)][::-1], kappa) else: movs(d, a[0][1]) @@ -398,16 +401,16 @@ def PreMulC_end(p, a, c, m, z): def PreMulC(a): p = [type(a[0])() for i in range(len(a))] - instructions_base.set_global_instruction_type(a[0].instruction_type) + Compiler.instructions_base.set_global_instruction_type(a[0].instruction_type) PreMulC_without_inverses(p, a) - instructions_base.reset_global_instruction_type() + Compiler.instructions_base.reset_global_instruction_type() return p def KMulC(a): """ Return just the product of all items in a """ - from types import sint, cint + from Compiler.types import sint, cint p = sint() PreMulC_without_inverses(p, a) return p @@ -448,4 +451,4 @@ def Mod2(a_0, a, k, kappa, signed): # hack for circular dependency -from instructions import * +from Compiler.instructions import * diff --git a/Compiler/compilerLib.py b/Compiler/compilerLib.py index 55307f43..4d4561f7 100644 --- a/Compiler/compilerLib.py +++ b/Compiler/compilerLib.py @@ -1,7 +1,12 @@ +from __future__ import print_function +from past.builtins import execfile from Compiler.program import Program from Compiler.config import * from Compiler.exceptions import * -import instructions, instructions_base, types, comparison, library +import Compiler.instructions +import Compiler.instructions_base +import Compiler.types +import Compiler.comparison import random import time @@ -16,19 +21,19 @@ def run(args, options, param=-1, merge_opens=True, \ instructions. """ prog = Program(args, options, param) - instructions.program = prog - instructions_base.program = prog - types.program = prog - comparison.program = prog + Compiler.instructions.program = prog + Compiler.instructions_base.program = prog + Compiler.types.program = prog + Compiler.comparison.program = prog prog.DEBUG = debug VARS['program'] = prog - comparison.set_variant(options) + Compiler.comparison.set_variant(options) - print 'Compiling file', prog.infile + print('Compiling file', prog.infile) - if instructions_base.Instruction.count != 0: - print 'instructions count', instructions_base.Instruction.count - instructions_base.Instruction.count = 0 + if Compiler.instructions_base.Instruction.count != 0: + print('instructions count', Compiler.instructions_base.Instruction.count) + Compiler.instructions_base.Instruction.count = 0 prog.FIRST_PASS = False prog.reset_values() # make compiler modules directly accessible @@ -42,8 +47,8 @@ def run(args, options, param=-1, merge_opens=True, \ if prog.main_thread_running: prog.update_req(prog.curr_tape) - print 'Program requires:', repr(prog.req_num) - print 'Memory size:', prog.allocated_mem + print('Program requires:', repr(prog.req_num)) + print('Memory size:', prog.allocated_mem) # finalize the memory prog.finalize_memory() diff --git a/Compiler/core.py b/Compiler/core.py index 0fcad181..730f30cf 100644 --- a/Compiler/core.py +++ b/Compiler/core.py @@ -1,10 +1,21 @@ +from __future__ import division # This file is only used in the scripts for doing auto testing +from builtins import range +from past.utils import old_div +from builtins import object import operator from collections import defaultdict import sys +from functools import reduce -class Vector: + +if sys.version[0] == "3": + # If we're in python3, integers have unlimited size + long = int + + +class Vector(object): def __init__(self,value=0,size=0): self.v = [value] * size def store_in_mem(self,addr): @@ -98,20 +109,20 @@ class _register(long): store_in_mem = lambda x,y: None load_mem = classmethod(lambda cls,addr,size=None: cls(0) if size is None else Vector(cls(0),size)) get_random = classmethod(lambda cls,*args: cls(0)) - __add__ = lambda x,y: type(x)(long(x) + y) - __sub__ = lambda x,y: type(x)(long(x) - y) - __rsub__ = lambda x,y: type(x)(y - long(x)) - __mul__ = lambda x,y: type(x)(long(x) * y) - __div__ = lambda x,y: type(x)(long(x) / y) - __rdiv__ = lambda x,y: type(x)(y / long(x)) - __mod__ = lambda x,y: type(x)(long(x) % y) - __rmod__ = lambda x,y: type(x)(y % long(x)) - __neg__ = lambda x: type(x)(-long(x)) - __pow__ = lambda x,y: type(x)(long(x) ** y) - __lshift__ = lambda x,y: type(x)(long(x) << y) - __rshift__ = lambda x,y: type(x)(long(x) >> y) - __rlshift__ = lambda x,y: type(x)(y << long(x)) - __rrshift__ = lambda x,y: type(x)(y >> long(x)) + __add__ = lambda x,y: type(x)(int(x) + y) + __sub__ = lambda x,y: type(x)(int(x) - y) + __rsub__ = lambda x,y: type(x)(y - int(x)) + __mul__ = lambda x,y: type(x)(int(x) * y) + __div__ = lambda x,y: type(x)(old_div(int(x), y)) + __rdiv__ = lambda x,y: type(x)(old_div(y, int(x))) + __mod__ = lambda x,y: type(x)(int(x) % y) + __rmod__ = lambda x,y: type(x)(y % int(x)) + __neg__ = lambda x: type(x)(-int(x)) + __pow__ = lambda x,y: type(x)(int(x) ** y) + __lshift__ = lambda x,y: type(x)(int(x) << y) + __rshift__ = lambda x,y: type(x)(int(x) >> y) + __rlshift__ = lambda x,y: type(x)(y << int(x)) + __rrshift__ = lambda x,y: type(x)(y >> int(x)) __radd__ = __add__ __rmul__ = __mul__ @@ -128,18 +139,18 @@ class _sbit(_register): class _sregint(_register): - __and__ = lambda self,other,x=None,y=None: sregint(long(self) * other) if (isinstance(other, _sbit)) else sregint(long(self) & other) - __or__ = lambda self, other, x=None, y=None: sregint(long(self) | other) - __xor__ = lambda self, other, x=None, y=None: sregint(long(self) ^ other) + __and__ = lambda self,other,x=None,y=None: sregint(int(self) * other) if (isinstance(other, _sbit)) else sregint(int(self) & other) + __or__ = lambda self, other, x=None, y=None: sregint(int(self) | other) + __xor__ = lambda self, other, x=None, y=None: sregint(int(self) ^ other) - mul_2_sint = lambda self, other, x = None, y = None: (sregint((long (self) * other ) >> 64), sregint((long (self) * other ) % (2 ** 64))) + mul_2_sint = lambda self, other, x = None, y = None: (sregint((int (self) * other ) >> 64), sregint((int (self) * other ) % (2 ** 64))) reveal = lambda self: regint(self) - less_than = lambda self,other,x=None,y=None: sbit(long(self) < other) - greater_than = lambda self,other,x=None,y=None: sbit(long(self) > other) - less_equal = lambda self,other,x=None,y=None: sbit(long(self) <= other) - greater_equal = lambda self,other,x=None,y=None: sbit(long(self) >= other) - equal = lambda self,other,x=None,y=None: sbit(long(self) == other) - not_equal = lambda self,other,x=None,y=None: sbit(long(self) != other) + less_than = lambda self,other,x=None,y=None: sbit(int(self) < other) + greater_than = lambda self,other,x=None,y=None: sbit(int(self) > other) + less_equal = lambda self,other,x=None,y=None: sbit(int(self) <= other) + greater_equal = lambda self,other,x=None,y=None: sbit(int(self) >= other) + equal = lambda self,other,x=None,y=None: sbit(int(self) == other) + not_equal = lambda self,other,x=None,y=None: sbit(int(self) != other) __lt__ = less_than __gt__ = greater_than @@ -147,7 +158,7 @@ class _sregint(_register): __ge__ = greater_equal __eq__ = equal __ne__ = not_equal - __neg__ = lambda self: sregint(-long(self)) + __neg__ = lambda self: sregint(-int(self)) __rand__ = __and__ __ror__ = __or__ @@ -161,12 +172,12 @@ class _sregint(_register): sregint.type = _sregint class _sint(_register): - less_than = lambda self,other,x=None,y=None: sint(long(self) < other) - greater_than = lambda self,other,x=None,y=None: sint(long(self) > other) - less_equal = lambda self,other,x=None,y=None: sint(long(self) <= other) - greater_equal = lambda self,other,x=None,y=None: sint(long(self) >= other) - equal = lambda self,other,x=None,y=None: sint(long(self) == other) - not_equal = lambda self,other,x=None,y=None: sint(long(self) != other) + less_than = lambda self,other,x=None,y=None: sint(int(self) < other) + greater_than = lambda self,other,x=None,y=None: sint(int(self) > other) + less_equal = lambda self,other,x=None,y=None: sint(int(self) <= other) + greater_equal = lambda self,other,x=None,y=None: sint(int(self) >= other) + equal = lambda self,other,x=None,y=None: sint(int(self) == other) + not_equal = lambda self,other,x=None,y=None: sint(int(self) != other) reveal = lambda self: cint(self) mod2m = lambda self,other,x=None,y=None: self % 2**other pow2 = lambda self,x=None,y=None: 2**self @@ -179,7 +190,7 @@ class _sint(_register): __ge__ = greater_equal __eq__ = equal __ne__ = not_equal - __neg__ = lambda self: sint(-long(self)) + __neg__ = lambda self: sint(-int(self)) sint = lambda x=0,size=None: (x if isinstance(x, Vector) else _sint(x)) if size is None else Vector(_sint(x),size) sint.load_mem = _sint.load_mem @@ -198,7 +209,7 @@ class _cint(_register): cint.load_mem = cint cint.get_random = cint -class A: +class A(object): def malloc(self, size, reg_type): pass def run_tape(self, f, x): @@ -399,7 +410,7 @@ class _cfix(_fixregister): program.security = None program.public_input = lambda x: None -class MPCThread: +class MPCThread(object): def __init__(self, target, name, args=[]): target(*args) def start(self, arg=None): @@ -423,7 +434,7 @@ def intify(a): return [intify(x) for x in a] else: return regint(a) if isinstance(a, int) else a -class FunctionTape: +class FunctionTape(object): def __init__(self, f): self.f = f def __call__(self, *args): @@ -480,7 +491,7 @@ def __init__(self,n,m,t,*args): else_then = end_if = lambda: None do_while = lambda x: x() while_do = lambda y,*args: lambda x: x(*args) -class MemValue: +class MemValue(object): def __init__(x,y): if not isinstance(y, (_sint,_cint,float)): y = regint(y) diff --git a/Compiler/dijkstra.py b/Compiler/dijkstra.py index daa01e30..46a86dfd 100644 --- a/Compiler/dijkstra.py +++ b/Compiler/dijkstra.py @@ -1,3 +1,10 @@ +from __future__ import print_function +from __future__ import division +from builtins import str +from builtins import zip +from builtins import range +from past.utils import old_div +from builtins import object from Compiler.oram import * if 'Emulation' in sys.path: @@ -86,8 +93,8 @@ def __init__(self, max_size, oram_type=ORAM, init_rounds=-1, int_type=sint): self.size = MemValue(int_type(0)) self.int_type = int_type self.basic_type = basic_type - print 'heap: %d levels, depth %d, size %d, index size %d' % \ - (self.levels, self.depth, self.heap.oram.size, self.value_index.size) + print('heap: %d levels, depth %d, size %d, index size %d' % \ + (self.levels, self.depth, self.heap.oram.size, self.value_index.size)) def update(self, value, prio, for_real=True): self._update(self.basic_type.hard_conv(value), \ self.basic_type.hard_conv(prio), \ @@ -217,7 +224,7 @@ def dump(self, msg=''): def dijkstra(source, edges, e_index, oram_type, n_loops=None, int_type=sint): basic_type = int_type.basic_type - vert_loops = n_loops * e_index.size / edges.size \ + vert_loops = old_div(n_loops * e_index.size, edges.size) \ if n_loops else -1 dist = oram_type(e_index.size, entry_size=(32,log2(e_index.size)), \ init_rounds=vert_loops, value_type=basic_type) @@ -287,7 +294,7 @@ def test_dijkstra(G, source, oram_type=ORAM, n_loops=None, int_type=sint): cint(i).print_reg('edge') time() edges[i] = edges_list[i] - vert_loops = n_loops * e_index.size / edges.size \ + vert_loops = old_div(n_loops * e_index.size, edges.size) \ if n_loops else e_index.size for i in range(vert_loops): cint(i).print_reg('vert') @@ -307,7 +314,7 @@ def f(i): time() neighbour = ((i >> 1) + 2 * (i % 2) - 1 + n) % n edges[i] = (neighbour, 1, i % 2) - vert_loops = n_loops * e_index.size / edges.size \ + vert_loops = old_div(n_loops * e_index.size, edges.size) \ if n_loops else e_index.size @for_range(vert_loops) def f(i): @@ -390,14 +397,14 @@ def __repr__(self): class Vector(object): """ Works like a vector. """ def __add__(self, other): - print 'add', type(self) + print('add', type(self)) res = type(self)(len(self)) @for_range(len(self)) def f(i): res[i] = self[i] + other[i] return res def __sub__(self, other): - print 'sub', type(other) + print('sub', type(other)) res = type(other)(len(self)) @for_range(len(self)) def f(i): @@ -412,7 +419,7 @@ def f(i): res[0] += self[i] * other[i] return res[0] else: - print 'mul', type(self) + print('mul', type(self)) res = type(self)(len(self)) @for_range_parallel(1024, len(self)) def f(i): @@ -477,7 +484,7 @@ def binarymin(A): if len(A) == 1: return [1], A[0] else: - half = len(A) / 2 + half = old_div(len(A), 2) A_prime = VectorArray(half) B = IntVectorArray(half) i = IntVectorArray(len(A)) diff --git a/Compiler/floatingpoint.py b/Compiler/floatingpoint.py index 6f320014..de072944 100644 --- a/Compiler/floatingpoint.py +++ b/Compiler/floatingpoint.py @@ -1,597 +1,602 @@ -## -# @file -# floating point operations -# File documentation -# -from math import log, floor, ceil -from Compiler.instructions import * -import types -import comparison -import program - - -## -## Helper functions for floating point arithmetic -## - - -def two_power(n): - if isinstance(n, int) and n < 31: - return 2**n - else: - max = types.cint(1) << 31 - res = 2**(n%31) - for i in range(n / 31): - res *= max - return res - -def shift_two(n, pos): - if pos < 63: - return n >> pos - else: - res = (n >> (pos%63)) - for i in range(pos / 63): - res >>= 63 - return res - -## -# Simplified less than test for sfloat. -# Returns 0 if there is error. -# @param fl_a: always an sfloat -# @param fl_b: can be sfloat or cfloat -# @return sint \{0,1\} where a < 0. -def FLLT (fl_a, fl_b): - t = fl_a.err - if isinstance(fl_b, types.sfloat): - t = t + fl_b.err - t = t == 0 - z1 = fl_a.z - z2 = fl_b.z - s1 = fl_a.s - s2 = fl_b.s - a = fl_a.p.less_than(fl_b.p, fl_a.plen, fl_a.kappa) - c = EQZ(fl_a.p - fl_b.p, fl_a.plen, fl_a.kappa) - d = ((1 - 2 * fl_a.s) * fl_a.v).less_than((1 - 2 * fl_b.s) * fl_b.v, fl_a.vlen + 1, fl_a.kappa) - cd = c * d - ca = c * a - b1 = cd + a - ca - b2 = cd + 1 + ca - c - a - s12 = fl_a.s * fl_b.s - z12 = fl_a.z * fl_b.z - b = (z1 - z12) * (1 - s2) + (z2 - z12) * s1 + (1 + z12 - z1 - z2) * \ - (s1 - s12 + (1 + s12 - s1 - s2) * b1 + s12 * b2) * t - return b - - -def EQZ(a, k, kappa): - r_dprime = types.sint() - r_prime = types.sint() - c = types.cint() - d = [None]*k - r = [types.sint() for i in range(k)] - comparison.PRandM(r_dprime, r_prime, r, k, k, kappa) - startopen(a + two_power(k) * r_dprime + r_prime)# + 2**(k-1)) - stopopen(c) - for i,b in enumerate(bits(c, k)): - d[i] = b + r[i] - 2*b*r[i] - return 1 - KOR(d, kappa) - - -## -# Simplified less than zero test for sfloat. -# Returns 0 if there is error. -# @param a: input to be zero tested -# @return sint \{0,1\} where a < 0. -def FLLTZ(a): - return (a.s * (1 - a.z)) * (a.err == 0) - - -## -# Simplified zero test for sfloat. -# Returns 0 if there is error. -# @param a: input to be zero tested -# @return sint \{0,1\} where a == 0. -def FLEQZ(a): - return a.z * (a.err == 0) - - -## -# Simplified greater than zero test for sfloat. -# Returns 0 if there is error. -# @param a: input to be zero tested -# @return sint \{0,1\} where a > 0. -def FLGTZ(a): - return ((1 - a.s) * (1 - a.z)) * (a.err == 0) - - -## -# Simplified less equal than zero test for sfloat. -# Returns 0 if there is error. -# @param a: input to be zero tested -# @return sint \{0,1\} where a <= 0. -def FLLEZ(a): - return a.s * (a.err == 0) - - -## -# Simplified greater equal than zero test for sfloat. -# Returns 0 if there is error. -# @param a: input to be zero tested -# @return sint \{0,1\} where a >= 0. -def FLGEZ(a): - return (1 - a.s) * (a.err == 0) - - -def bits(a,m): - """ Get the bits of an int """ - if isinstance(a, int): - res = [None]*m - for i in range(m): - res[i] = a & 1 - a >>= 1 - else: - c = [[types.cint() for i in range(m)] for i in range(2)] - res = [types.cint() for i in range(m)] - modci(res[0], a, 2) - c[1][0] = a - for i in range(1,m): - subc(c[0][i], c[1][i-1], res[i-1]) - divci(c[1][i], c[0][i], 2) - modci(res[i], c[1][i], 2) - return res - -def carry(b, a, compute_p=True): - """ Carry propogation: - (p,g) = (p_2, g_2)o(p_1, g_1) -> (p_1 & p_2, g_2 | (p_2 & g_1)) - """ - if compute_p: - t1 = a[0] * b[0] - else: - t1 = None - t2 = a[1] + a[0] * b[1] - return (t1, t2) - -def or_op(a, b, void=None): - return a + b - a * b - -def mul_op(a, b, void=None): - return a * b - -def xor_op(a, b, void=None): - return a + b - 2* a * b - - -def PreORC(a, kappa=None, m=None, raw=False): - k = len(a) - if k == 1: - return [a[0]] - m = m or k - max_k = int(log(program.Program.prog.P) / log(2)) - kappa - if k <= max_k: - p = [None] * m - if m == k: - p[0] = a[0] - t = [types.sint() for i in range(m)] - b = comparison.PreMulC([a[i] + 1 for i in range(k)]) - for i in range(m): - comparison.Mod2(t[i], b[k-1-i], k, kappa, False) - p[m-1-i] = 1 - t[i] - return p - else: - # not constant-round anymore - s = [PreORC(a[i:i+max_k], kappa, raw=raw) for i in range(0,k,max_k)] - t = PreORC([si[-1] for si in s[:-1]], kappa, raw=raw) - return sum(([or_op(x, y) for x in si] for si,y in zip(s[1:],t)), s[0]) - -def PreOpL(op, items): - """ - Uses algorithm from SecureSCM WP9 deliverable. - - op must be a binary function that outputs a new register - """ - k = len(items) - logk = int(ceil(log(k,2))) - kmax = 2**logk - output = list(items) - for i in range(logk): - for j in range(kmax/(2**(i+1))): - y = two_power(i) + j*two_power(i+1) - 1 - for z in range(1, 2**i+1): - if y+z < k: - output[y+z] = op(output[y], output[y+z], j != 0) - return output - -def PreOpN(op, items): - """ Naive PreOp algorithm """ - k = len(items) - output = [None]*k - output[0] = items[0] - for i in range(1, k): - output[i] = op(output[i-1], items[i]) - return output - -def PreOR(a, kappa=None, raw=False): - if comparison.const_rounds: - return PreORC(a, kappa, raw=raw) - else: - return PreOpL(or_op, a) - -def KOpL(op, a): - k = len(a) - if k == 1: - return a[0] - else: - t1 = KOpL(op, a[:k/2]) - t2 = KOpL(op, a[k/2:]) - return op(t1, t2) - -def KORL(a, kappa): - """ log rounds k-ary OR """ - k = len(a) - if k == 1: - return a[0] - else: - t1 = KORL(a[:k/2], kappa) - t2 = KORL(a[k/2:], kappa) - return t1 + t2 - t1*t2 - -def KORC(a, kappa): - return PreORC(a, kappa, 1)[0] - -def KOR(a, kappa): - if comparison.const_rounds: - return KORC(a, kappa) - else: - return KORL(a, None) - -def KMul(a): - if comparison.const_rounds: - return comparison.KMulC(a) - else: - return KOpL(mul_op, a) - -def FlAbs(a): - return types.sfloat(v = a.v, p = a.p, z = a.z, s = types.sint(0), err = a.err) - -def Inv(a): - """ Invert a non-zero value """ - t = [types.sint() for i in range(2)] - c = [types.cint() for i in range(2)] - one = types.cint() - ldi(one, 1) - square(t[0],t[1]); - s = t[0]*a - asm_open(c[0], s) - # avoid division by zero for benchmarking - divc(c[1], one, c[0]) - #divc(c[1], c[0], one) - return c[1]*t[0] - -def BitAdd(a, b, bits_to_compute=None): - """ Add the bits a[k-1], ..., a[0] and b[k-1], ..., b[0], return k+1 - bits s[0], ... , s[k] """ - k = len(a) - if not bits_to_compute: - bits_to_compute = range(k) - d = [None] * k - for i in range(1,k): - #assert(a[i].value == 0 or a[i].value == 1) - #assert(b[i].value == 0 or b[i].value == 1) - t = a[i]*b[i] - d[i] = (a[i] + b[i] - 2*t, t) - #assert(d[i][0].value == 0 or d[i][0].value == 1) - d[0] = (None, a[0]*b[0]) - pg = PreOpL(carry, d) - c = [pair[1] for pair in pg] - - # (for testing) - def print_state(): - print 'a: ', - for i in range(k): - print '%d ' % a[i].value, - print '\nb: ', - for i in range(k): - print '%d ' % b[i].value, - print '\nd: ', - for i in range(k): - print '%d ' % d[i][0].value, - print '\n ', - for i in range(k): - print '%d ' % d[i][1].value, - print '\n\npg:', - for i in range(k): - print '%d ' % pg[i][0].value, - print '\n ', - for i in range(k): - print '%d ' % pg[i][1].value, - print '' - - for bit in c: - pass#assert(bit.value == 0 or bit.value == 1) - s = [None] * (k+1) - if 0 in bits_to_compute: - s[0] = a[0] + b[0] - 2*c[0] - bits_to_compute.remove(0) - #assert(c[0].value == a[0].value*b[0].value) - #assert(s[0].value == 0 or s[0].value == 1) - for i in bits_to_compute: - s[i] = a[i] + b[i] + c[i-1] - 2*c[i] - try: - pass#assert(s[i].value == 0 or s[i].value == 1) - except AssertionError: - print '#assertion failed in BitAdd for s[%d]' % i - print_state() - s[k] = c[k-1] - #print_state() - return s - -def BitDec(a, k, m, kappa, bits_to_compute=None): - r_dprime = types.sint() - r_prime = types.sint() - c = types.cint() - r = [types.sint() for i in range(m)] - comparison.PRandM(r_dprime, r_prime, r, k, m, kappa) - #assert(r_prime.value == sum(r[i].value*2**i for i in range(m)) % comparison.program.P) - pow2 = two_power(k + kappa) - asm_open(c, pow2 + two_power(k) + a - two_power(m)*r_dprime - r_prime) - #rval = 2**m*r_dprime.value + r_prime.value - #assert(rval % 2**m == r_prime.value) - #assert(rval == (2**m*r_dprime.value + sum(r[i].value*2**i for i in range(m)) % comparison.program.P )) - try: - pass#assert(c.value == (2**(k + kappa) + 2**k + (a.value%2**k) - rval) % comparison.program.P) - except AssertionError: - print 'BitDec assertion failed' - print 'a =', a.value - print 'a mod 2^%d =' % k, (a.value % 2**k) - return BitAdd(list(bits(c,m)), r, bits_to_compute)[:-1] - - -def Pow2(a, l, kappa): - m = int(ceil(log(l, 2))) - t = BitDec(a, m, m, kappa) - x = [types.sint() for i in range(m)] - pow2k = [types.cint() for i in range(m)] - for i in range(m): - pow2k[i] = two_power(2**i) - t[i] = t[i]*pow2k[i] + 1 - t[i] - return KMul(t) - -def B2U(a, l, kappa): - pow2a = Pow2(a, l, kappa) - #assert(pow2a.value == 2**a.value) - r = [types.sint() for i in range(l)] - t = types.sint() - c = types.cint() - for i in range(l): - bit(r[i]) - comparison.PRandInt(t, kappa) - asm_open(c, pow2a + two_power(l) * t + sum(two_power(i)*r[i] for i in range(l))) - comparison.program.curr_tape.require_bit_length(l + kappa) - c = list(bits(c, l)) - x = [c[i] + r[i] - 2*c[i]*r[i] for i in range(l)] - #print ' '.join(str(b.value) for b in x) - y = PreOR(x, kappa) - #print ' '.join(str(b.value) for b in y) - return [1 - y[i] for i in range(l)], pow2a - -def Trunc(a, l, m, kappa, compute_modulo=False): - """ Oblivious truncation by secret m """ - if l == 1: - if compute_modulo: - return a * m, 1 + m - else: - return a * (1 - m) - r = [types.sint() for i in range(l)] - r_dprime = types.sint(0) - r_prime = types.sint(0) - rk = types.sint() - c = types.cint() - ci = [types.cint() for i in range(l)] - d = types.sint() - x, pow2m = B2U(m, l, kappa) - #assert(pow2m.value == 2**m.value) - #assert(sum(b.value for b in x) == m.value) - for i in range(l): - bit(r[i]) - t1 = two_power(i) * r[i] - t2 = t1*x[i] - r_prime += t2 - r_dprime += t1 - t2 - #assert(r_prime.value == (sum(2**i*x[i].value*r[i].value for i in range(l)) % comparison.program.P)) - comparison.PRandInt(rk, kappa) - r_dprime += two_power(l) * rk - #assert(r_dprime.value == (2**l * rk.value + sum(2**i*(1 - x[i].value)*r[i].value for i in range(l)) % comparison.program.P)) - asm_open(c, a + r_dprime + r_prime) - for i in range(1,l): - ci[i] = c % two_power(i) - #assert(ci[i].value == c.value % 2**i) - c_dprime = sum(ci[i]*(x[i-1] - x[i]) for i in range(1,l)) - #assert(c_dprime.value == (sum(ci[i].value*(x[i-1].value - x[i].value) for i in range(1,l)) % comparison.program.P)) - lts(d, c_dprime, r_prime, l, kappa) - if compute_modulo: - b = c_dprime - r_prime + pow2m * d - return b, pow2m - else: - pow2inv = Inv(pow2m) - #assert(pow2inv.value * pow2m.value % comparison.program.P == 1) - b = (a - c_dprime + r_prime) * pow2inv - d - return b - -def TruncRoundNearestAdjustOverflow(a, length, target_length, kappa): - t = comparison.TruncRoundNearest(a, length, length - target_length, kappa) - overflow = t.greater_equal(two_power(target_length), target_length + 1, kappa) - s = (1 - overflow) * t + overflow * t / 2 - return s, overflow - -def Int2FL(a, gamma, l, kappa): - lam = gamma - 1 - s = types.sint() - comparison.LTZ(s, a, gamma, kappa) - z = EQZ(a, gamma, kappa) - a = (1 - 2 * s) * a - - a_bits = BitDec(a, lam, lam, kappa) - a_bits.reverse() - b = PreOR(a_bits, kappa) - t = a * (1 + sum(2**i * (1 - b_i) for i,b_i in enumerate(b))) - p = - (lam - sum(b)) - if lam > l: - if types.sfloat.round_nearest: - v, overflow = TruncRoundNearestAdjustOverflow(t, gamma - 1, l, kappa) - p = p + overflow - else: - v = types.sint() - comparison.Trunc(v, t, gamma - 1, gamma - l - 1, kappa, False) - #TODO: Shouldnt this be only gamma - else: - v = 2**(l-gamma+1) * t - p = (p + gamma - 1 - l) * (1 -z) - return v, p, z, s - - -## -# Original Function that converts inputs to -# floats, as implemented in legacy code (sfloat). -# It looks like a special adaptation from -# [ABZ13] -# @param v: int or cint value to be transformed to sfloat -# @param vlen: length of v (usually l) in paper -# @param plen: bit-length of supported precision -# @return all basic components of a floating point as in [ABZ13] -def convert_float(v, vlen, plen): - if v < 0: - s = 1 - else: - s = 0 - if v == 0: - v = 0 - p = 0 - z = 1 - else: - p = int(floor(log(abs(v), 2))) - vlen + 1 - vv = v - v = int(round(abs(v) * 2 ** (-p))) - if v == 2 ** vlen: - p += 1 - v /= 2 - z = 0 - if p < -2 ** (plen - 1): - print 'Warning: %e truncated to zero' % vv - v, p, z = 0, 0, 1 - if p >= 2 ** (plen - 1): # use it for the comparison - raise CompilerError('Cannot convert %s to float ' \ - 'with %d exponent bits' % (vv, plen)) - return v, p, z, s - - -def FLRound(x, mode): - """ Rounding with floating point output. - *mode*: 0 -> floor, 1 -> ceil, -1 > trunc """ - v1, p1, z1, s1, l, k = x.v, x.p, x.z, x.s, x.vlen, x.plen - a = types.sint() - comparison.LTZ(a, p1, k, x.kappa) - b = p1.less_than(-l + 1, k, x.kappa) - v2, inv_2pow_p1 = Trunc(v1, l, -a * (1 - b) * x.p, x.kappa, True) - c = EQZ(v2, l, x.kappa) - if mode == -1: - away_from_zero = 0 - mode = x.s - else: - away_from_zero = mode + s1 - 2 * mode * s1 - v = v1 - v2 + (1 - c) * inv_2pow_p1 * away_from_zero - d = v.equal(two_power(l), l + 1, x.kappa) - v = d * two_power(l-1) + (1 - d) * v - v = a * ((1 - b) * v + b * away_from_zero * two_power(l-1)) + (1 - a) * v1 - s = (1 - b * mode) * s1 - z = or_op(EQZ(v, l, x.kappa), z1) - v = v * (1 - z) - p = ((p1 + d * a) * (1 - b) + b * away_from_zero * (1 - l)) * (1 - z) - return v, p, z, s - -def TruncPr(a, k, m, kappa=None): - """ Probabilistic truncation [a/2^m + u] - where Pr[u = 1] = (a % 2^m) / 2^m - """ - if isinstance(a, types.cint): - return shift_two(a, m) - - if kappa is None: - kappa = 40 - - b = two_power(k-1) + a - r_prime, r_dprime = types.sint(), types.sint() - comparison.PRandM(r_dprime, r_prime, [types.sint() for i in range(m)], - k, m, kappa) - two_to_m = two_power(m) - r = two_to_m * r_dprime + r_prime - c = (b + r).reveal() - c_prime = c % two_to_m - a_prime = c_prime - r_prime - d = (a - a_prime) / two_to_m - return d - -def SDiv(a, b, l, kappa): - theta = int(ceil(log(l / 3.5) / log(2))) - alpha = two_power(2*l) - beta = 1 / types.cint(two_power(l)) - w = types.cint(int(2.9142 * two_power(l))) - 2 * b - x = alpha - b * w - y = a * w - y = TruncPr(y, 2 * l, l, kappa) - x2 = types.sint() - comparison.Mod2m(x2, x, 2 * l + 1, l, kappa, False) - x1 = (x - x2) * beta - for i in range(theta-1): - y = y * (x1 + two_power(l)) + TruncPr(y * x2, 2 * l, l, kappa) - y = TruncPr(y, 2 * l + 1, l + 1, kappa) - x = x1 * x2 + TruncPr(x2**2, 2 * l + 1, l + 1, kappa) - x = x1 * x1 + TruncPr(x, 2 * l + 1, l - 1, kappa) - x2 = types.sint() - comparison.Mod2m(x2, x, 2 * l, l, kappa, False) - x1 = (x - x2) * beta - y = y * (x1 + two_power(l)) + TruncPr(y * x2, 2 * l, l, kappa) - y = TruncPr(y, 2 * l + 1, l - 1, kappa) - return y - -def SDiv_mono(a, b, l, kappa): - theta = int(ceil(log(l / 3.5) / log(2))) - alpha = two_power(2*l) - w = types.cint(int(2.9142 * two_power(l))) - 2 * b - x = alpha - b * w - y = a * w - y = TruncPr(y, 2 * l + 1, l + 1, kappa) - for i in range(theta-1): - y = y * (alpha + x) - # keep y with l bits - y = TruncPr(y, 3 * l, 2 * l, kappa) - x = x**2 - # keep x with 2l bits - x = TruncPr(x, 4 * l, 2 * l, kappa) - y = y * (alpha + x) - y = TruncPr(y, 3 * l, 2 * l, kappa) - return y - -## -# SDiv as annotated in ABZS12. It perfroms -# division using rapson newton from approx on -# 2^l -def SDiv_ABZS12(a, b, l, kappa): - theta = int(ceil(log(l, 2))) - x = b - y = a - for i in range(theta -1): - y = y * ((2 ** (l + 1)) - x) - y = TruncPr(y, 2 * l + 1, l, kappa) - x = x * ((2 ** (l + 1)) - x) - x = TruncPr(x, 2 * l + 1, l, kappa) - y = y * ((2 ** (l + 1)) - x) - y = TruncPr(y, 2 * l + 1, l, kappa) - return y - -def AdditionKOp(a,b): - return a + b - - -def SolvedBits(x_bits, k): - pow_of_two= [x_bits[i] * 2 ** i for i in range(k)] - return KOpL(AdditionKOp, pow_of_two) +from __future__ import print_function +from __future__ import division +## +# @file +# floating point operations +# File documentation +# +from builtins import zip +from builtins import range +from past.utils import old_div +from math import log, floor, ceil +from Compiler.instructions import * +import Compiler.types +import Compiler.comparison +import Compiler.program + + +## +## Helper functions for floating point arithmetic +## + + +def two_power(n): + if isinstance(n, int) and n < 31: + return 2**n + else: + max = Compiler.types.cint(1) << 31 + res = 2**(n%31) + for i in range(old_div(n, 31)): + res *= max + return res + +def shift_two(n, pos): + if pos < 63: + return n >> pos + else: + res = (n >> (pos%63)) + for i in range(old_div(pos, 63)): + res >>= 63 + return res + +## +# Simplified less than test for sfloat. +# Returns 0 if there is error. +# @param fl_a: always an sfloat +# @param fl_b: can be sfloat or cfloat +# @return sint \{0,1\} where a < 0. +def FLLT (fl_a, fl_b): + t = fl_a.err + if isinstance(fl_b, Compiler.types.sfloat): + t = t + fl_b.err + t = t == 0 + z1 = fl_a.z + z2 = fl_b.z + s1 = fl_a.s + s2 = fl_b.s + a = fl_a.p.less_than(fl_b.p, fl_a.plen, fl_a.kappa) + c = EQZ(fl_a.p - fl_b.p, fl_a.plen, fl_a.kappa) + d = ((1 - 2 * fl_a.s) * fl_a.v).less_than((1 - 2 * fl_b.s) * fl_b.v, fl_a.vlen + 1, fl_a.kappa) + cd = c * d + ca = c * a + b1 = cd + a - ca + b2 = cd + 1 + ca - c - a + s12 = fl_a.s * fl_b.s + z12 = fl_a.z * fl_b.z + b = (z1 - z12) * (1 - s2) + (z2 - z12) * s1 + (1 + z12 - z1 - z2) * \ + (s1 - s12 + (1 + s12 - s1 - s2) * b1 + s12 * b2) * t + return b + + +def EQZ(a, k, kappa): + r_dprime = Compiler.types.sint() + r_prime = Compiler.types.sint() + c = Compiler.types.cint() + d = [None]*k + r = [Compiler.types.sint() for i in range(k)] + Compiler.comparison.PRandM(r_dprime, r_prime, r, k, k, kappa) + startopen(a + two_power(k) * r_dprime + r_prime)# + 2**(k-1)) + stopopen(c) + for i,b in enumerate(bits(c, k)): + d[i] = b + r[i] - 2*b*r[i] + return 1 - KOR(d, kappa) + + +## +# Simplified less than zero test for sfloat. +# Returns 0 if there is error. +# @param a: input to be zero tested +# @return sint \{0,1\} where a < 0. +def FLLTZ(a): + return (a.s * (1 - a.z)) * (a.err == 0) + + +## +# Simplified zero test for sfloat. +# Returns 0 if there is error. +# @param a: input to be zero tested +# @return sint \{0,1\} where a == 0. +def FLEQZ(a): + return a.z * (a.err == 0) + + +## +# Simplified greater than zero test for sfloat. +# Returns 0 if there is error. +# @param a: input to be zero tested +# @return sint \{0,1\} where a > 0. +def FLGTZ(a): + return ((1 - a.s) * (1 - a.z)) * (a.err == 0) + + +## +# Simplified less equal than zero test for sfloat. +# Returns 0 if there is error. +# @param a: input to be zero tested +# @return sint \{0,1\} where a <= 0. +def FLLEZ(a): + return a.s * (a.err == 0) + + +## +# Simplified greater equal than zero test for sfloat. +# Returns 0 if there is error. +# @param a: input to be zero tested +# @return sint \{0,1\} where a >= 0. +def FLGEZ(a): + return (1 - a.s) * (a.err == 0) + + +def bits(a,m): + """ Get the bits of an int """ + if isinstance(a, int): + res = [None]*m + for i in range(m): + res[i] = a & 1 + a >>= 1 + else: + c = [[Compiler.types.cint() for i in range(m)] for i in range(2)] + res = [Compiler.types.cint() for i in range(m)] + modci(res[0], a, 2) + c[1][0] = a + for i in range(1,m): + subc(c[0][i], c[1][i-1], res[i-1]) + divci(c[1][i], c[0][i], 2) + modci(res[i], c[1][i], 2) + return res + +def carry(b, a, compute_p=True): + """ Carry propogation: + (p,g) = (p_2, g_2)o(p_1, g_1) -> (p_1 & p_2, g_2 | (p_2 & g_1)) + """ + if compute_p: + t1 = a[0] * b[0] + else: + t1 = None + t2 = a[1] + a[0] * b[1] + return (t1, t2) + +def or_op(a, b, void=None): + return a + b - a * b + +def mul_op(a, b, void=None): + return a * b + +def xor_op(a, b, void=None): + return a + b - 2* a * b + + +def PreORC(a, kappa=None, m=None, raw=False): + k = len(a) + if k == 1: + return [a[0]] + m = m or k + max_k = int(old_div(log(Compiler.program.Program.prog.P), log(2))) - kappa + if k <= max_k: + p = [None] * m + if m == k: + p[0] = a[0] + t = [Compiler.types.sint() for i in range(m)] + b = Compiler.comparison.PreMulC([a[i] + 1 for i in range(k)]) + for i in range(m): + Compiler.comparison.Mod2(t[i], b[k-1-i], k, kappa, False) + p[m-1-i] = 1 - t[i] + return p + else: + # not constant-round anymore + s = [PreORC(a[i:i+max_k], kappa, raw=raw) for i in range(0,k,max_k)] + t = PreORC([si[-1] for si in s[:-1]], kappa, raw=raw) + return sum(([or_op(x, y) for x in si] for si,y in zip(s[1:],t)), s[0]) + +def PreOpL(op, items): + """ + Uses algorithm from SecureSCM WP9 deliverable. + + op must be a binary function that outputs a new register + """ + k = len(items) + logk = int(ceil(log(k,2))) + kmax = 2**logk + output = list(items) + for i in range(logk): + for j in range(old_div(kmax,(2**(i+1)))): + y = two_power(i) + j*two_power(i+1) - 1 + for z in range(1, 2**i+1): + if y+z < k: + output[y+z] = op(output[y], output[y+z], j != 0) + return output + +def PreOpN(op, items): + """ Naive PreOp algorithm """ + k = len(items) + output = [None]*k + output[0] = items[0] + for i in range(1, k): + output[i] = op(output[i-1], items[i]) + return output + +def PreOR(a, kappa=None, raw=False): + if Compiler.comparison.const_rounds: + return PreORC(a, kappa, raw=raw) + else: + return PreOpL(or_op, a) + +def KOpL(op, a): + k = len(a) + if k == 1: + return a[0] + else: + t1 = KOpL(op, a[:old_div(k,2)]) + t2 = KOpL(op, a[old_div(k,2):]) + return op(t1, t2) + +def KORL(a, kappa): + """ log rounds k-ary OR """ + k = len(a) + if k == 1: + return a[0] + else: + t1 = KORL(a[:old_div(k,2)], kappa) + t2 = KORL(a[old_div(k,2):], kappa) + return t1 + t2 - t1*t2 + +def KORC(a, kappa): + return PreORC(a, kappa, 1)[0] + +def KOR(a, kappa): + if Compiler.comparison.const_rounds: + return KORC(a, kappa) + else: + return KORL(a, None) + +def KMul(a): + if Compiler.comparison.const_rounds: + return Compiler.comparison.KMulC(a) + else: + return KOpL(mul_op, a) + +def FlAbs(a): + return Compiler.types.sfloat(v = a.v, p = a.p, z = a.z, s = Compiler.types.sint(0), err = a.err) + +def Inv(a): + """ Invert a non-zero value """ + t = [Compiler.types.sint() for i in range(2)] + c = [Compiler.types.cint() for i in range(2)] + one = Compiler.types.cint() + ldi(one, 1) + square(t[0],t[1]); + s = t[0]*a + asm_open(c[0], s) + # avoid division by zero for benchmarking + divc(c[1], one, c[0]) + #divc(c[1], c[0], one) + return c[1]*t[0] + +def BitAdd(a, b, bits_to_compute=None): + """ Add the bits a[k-1], ..., a[0] and b[k-1], ..., b[0], return k+1 + bits s[0], ... , s[k] """ + k = len(a) + if not bits_to_compute: + bits_to_compute = list(range(k)) + d = [None] * k + for i in range(1,k): + #assert(a[i].value == 0 or a[i].value == 1) + #assert(b[i].value == 0 or b[i].value == 1) + t = a[i]*b[i] + d[i] = (a[i] + b[i] - 2*t, t) + #assert(d[i][0].value == 0 or d[i][0].value == 1) + d[0] = (None, a[0]*b[0]) + pg = PreOpL(carry, d) + c = [pair[1] for pair in pg] + + # (for testing) + def print_state(): + print('a: ', end=' ') + for i in range(k): + print('%d ' % a[i].value, end=' ') + print('\nb: ', end=' ') + for i in range(k): + print('%d ' % b[i].value, end=' ') + print('\nd: ', end=' ') + for i in range(k): + print('%d ' % d[i][0].value, end=' ') + print('\n ', end=' ') + for i in range(k): + print('%d ' % d[i][1].value, end=' ') + print('\n\npg:', end=' ') + for i in range(k): + print('%d ' % pg[i][0].value, end=' ') + print('\n ', end=' ') + for i in range(k): + print('%d ' % pg[i][1].value, end=' ') + print('') + + for bit in c: + pass#assert(bit.value == 0 or bit.value == 1) + s = [None] * (k+1) + if 0 in bits_to_compute: + s[0] = a[0] + b[0] - 2*c[0] + bits_to_compute.remove(0) + #assert(c[0].value == a[0].value*b[0].value) + #assert(s[0].value == 0 or s[0].value == 1) + for i in bits_to_compute: + s[i] = a[i] + b[i] + c[i-1] - 2*c[i] + try: + pass#assert(s[i].value == 0 or s[i].value == 1) + except AssertionError: + print('#assertion failed in BitAdd for s[%d]' % i) + print_state() + s[k] = c[k-1] + #print_state() + return s + +def BitDec(a, k, m, kappa, bits_to_compute=None): + r_dprime = Compiler.types.sint() + r_prime = Compiler.types.sint() + c = Compiler.types.cint() + r = [Compiler.types.sint() for i in range(m)] + Compiler.comparison.PRandM(r_dprime, r_prime, r, k, m, kappa) + #assert(r_prime.value == sum(r[i].value*2**i for i in range(m)) % Compiler.comparison.program.P) + pow2 = two_power(k + kappa) + asm_open(c, pow2 + two_power(k) + a - two_power(m)*r_dprime - r_prime) + #rval = 2**m*r_dprime.value + r_prime.value + #assert(rval % 2**m == r_prime.value) + #assert(rval == (2**m*r_dprime.value + sum(r[i].value*2**i for i in range(m)) % Compiler.comparison.program.P )) + try: + pass#assert(c.value == (2**(k + kappa) + 2**k + (a.value%2**k) - rval) % Compiler.comparison.program.P) + except AssertionError: + print('BitDec assertion failed') + print('a =', a.value) + print('a mod 2^%d =' % k, (a.value % 2**k)) + return BitAdd(list(bits(c,m)), r, bits_to_compute)[:-1] + + +def Pow2(a, l, kappa): + m = int(ceil(log(l, 2))) + t = BitDec(a, m, m, kappa) + x = [Compiler.types.sint() for i in range(m)] + pow2k = [Compiler.types.cint() for i in range(m)] + for i in range(m): + pow2k[i] = two_power(2**i) + t[i] = t[i]*pow2k[i] + 1 - t[i] + return KMul(t) + +def B2U(a, l, kappa): + pow2a = Pow2(a, l, kappa) + #assert(pow2a.value == 2**a.value) + r = [Compiler.types.sint() for i in range(l)] + t = Compiler.types.sint() + c = Compiler.types.cint() + for i in range(l): + bit(r[i]) + Compiler.comparison.PRandInt(t, kappa) + asm_open(c, pow2a + two_power(l) * t + sum(two_power(i)*r[i] for i in range(l))) + Compiler.comparison.program.curr_tape.require_bit_length(l + kappa) + c = list(bits(c, l)) + x = [c[i] + r[i] - 2*c[i]*r[i] for i in range(l)] + #print ' '.join(str(b.value) for b in x) + y = PreOR(x, kappa) + #print ' '.join(str(b.value) for b in y) + return [1 - y[i] for i in range(l)], pow2a + +def Trunc(a, l, m, kappa, compute_modulo=False): + """ Oblivious truncation by secret m """ + if l == 1: + if compute_modulo: + return a * m, 1 + m + else: + return a * (1 - m) + r = [Compiler.types.sint() for i in range(l)] + r_dprime = Compiler.types.sint(0) + r_prime = Compiler.types.sint(0) + rk = Compiler.types.sint() + c = Compiler.types.cint() + ci = [Compiler.types.cint() for i in range(l)] + d = Compiler.types.sint() + x, pow2m = B2U(m, l, kappa) + #assert(pow2m.value == 2**m.value) + #assert(sum(b.value for b in x) == m.value) + for i in range(l): + bit(r[i]) + t1 = two_power(i) * r[i] + t2 = t1*x[i] + r_prime += t2 + r_dprime += t1 - t2 + #assert(r_prime.value == (sum(2**i*x[i].value*r[i].value for i in range(l)) % Compiler.comparison.program.P)) + Compiler.comparison.PRandInt(rk, kappa) + r_dprime += two_power(l) * rk + #assert(r_dprime.value == (2**l * rk.value + sum(2**i*(1 - x[i].value)*r[i].value for i in range(l)) % Compiler.comparison.program.P)) + asm_open(c, a + r_dprime + r_prime) + for i in range(1,l): + ci[i] = c % two_power(i) + #assert(ci[i].value == c.value % 2**i) + c_dprime = sum(ci[i]*(x[i-1] - x[i]) for i in range(1,l)) + #assert(c_dprime.value == (sum(ci[i].value*(x[i-1].value - x[i].value) for i in range(1,l)) % Compiler.comparison.program.P)) + lts(d, c_dprime, r_prime, l, kappa) + if compute_modulo: + b = c_dprime - r_prime + pow2m * d + return b, pow2m + else: + pow2inv = Inv(pow2m) + #assert(pow2inv.value * pow2m.value % Compiler.comparison.program.P == 1) + b = (a - c_dprime + r_prime) * pow2inv - d + return b + +def TruncRoundNearestAdjustOverflow(a, length, target_length, kappa): + t = Compiler.comparison.TruncRoundNearest(a, length, length - target_length, kappa) + overflow = t.greater_equal(two_power(target_length), target_length + 1, kappa) + s = (1 - overflow) * t + old_div(overflow * t, 2) + return s, overflow + +def Int2FL(a, gamma, l, kappa): + lam = gamma - 1 + s = Compiler.types.sint() + Compiler.comparison.LTZ(s, a, gamma, kappa) + z = EQZ(a, gamma, kappa) + a = (1 - 2 * s) * a + + a_bits = BitDec(a, lam, lam, kappa) + a_bits.reverse() + b = PreOR(a_bits, kappa) + t = a * (1 + sum(2**i * (1 - b_i) for i,b_i in enumerate(b))) + p = - (lam - sum(b)) + if lam > l: + if Compiler.types.sfloat.round_nearest: + v, overflow = TruncRoundNearestAdjustOverflow(t, gamma - 1, l, kappa) + p = p + overflow + else: + v = Compiler.types.sint() + Compiler.comparison.Trunc(v, t, gamma - 1, gamma - l - 1, kappa, False) + #TODO: Shouldnt this be only gamma + else: + v = 2**(l-gamma+1) * t + p = (p + gamma - 1 - l) * (1 -z) + return v, p, z, s + + +## +# Original Function that converts inputs to +# floats, as implemented in legacy code (sfloat). +# It looks like a special adaptation from +# [ABZ13] +# @param v: int or cint value to be transformed to sfloat +# @param vlen: length of v (usually l) in paper +# @param plen: bit-length of supported precision +# @return all basic components of a floating point as in [ABZ13] +def convert_float(v, vlen, plen): + if v < 0: + s = 1 + else: + s = 0 + if v == 0: + v = 0 + p = 0 + z = 1 + else: + p = int(floor(log(abs(v), 2))) - vlen + 1 + vv = v + v = int(round(abs(v) * 2 ** (-p))) + if v == 2 ** vlen: + p += 1 + v /= 2 + z = 0 + if p < -2 ** (plen - 1): + print('Warning: %e truncated to zero' % vv) + v, p, z = 0, 0, 1 + if p >= 2 ** (plen - 1): # use it for the comparison + raise CompilerError('Cannot convert %s to float ' \ + 'with %d exponent bits' % (vv, plen)) + return v, p, z, s + + +def FLRound(x, mode): + """ Rounding with floating point output. + *mode*: 0 -> floor, 1 -> ceil, -1 > trunc """ + v1, p1, z1, s1, l, k = x.v, x.p, x.z, x.s, x.vlen, x.plen + a = Compiler.types.sint() + Compiler.comparison.LTZ(a, p1, k, x.kappa) + b = p1.less_than(-l + 1, k, x.kappa) + v2, inv_2pow_p1 = Trunc(v1, l, -a * (1 - b) * x.p, x.kappa, True) + c = EQZ(v2, l, x.kappa) + if mode == -1: + away_from_zero = 0 + mode = x.s + else: + away_from_zero = mode + s1 - 2 * mode * s1 + v = v1 - v2 + (1 - c) * inv_2pow_p1 * away_from_zero + d = v.equal(two_power(l), l + 1, x.kappa) + v = d * two_power(l-1) + (1 - d) * v + v = a * ((1 - b) * v + b * away_from_zero * two_power(l-1)) + (1 - a) * v1 + s = (1 - b * mode) * s1 + z = or_op(EQZ(v, l, x.kappa), z1) + v = v * (1 - z) + p = ((p1 + d * a) * (1 - b) + b * away_from_zero * (1 - l)) * (1 - z) + return v, p, z, s + +def TruncPr(a, k, m, kappa=None): + """ Probabilistic truncation [a/2^m + u] + where Pr[u = 1] = (a % 2^m) / 2^m + """ + if isinstance(a, Compiler.types.cint): + return shift_two(a, m) + + if kappa is None: + kappa = 40 + + b = two_power(k-1) + a + r_prime, r_dprime = Compiler.types.sint(), Compiler.types.sint() + Compiler.comparison.PRandM(r_dprime, r_prime, [Compiler.types.sint() for i in range(m)], + k, m, kappa) + two_to_m = two_power(m) + r = two_to_m * r_dprime + r_prime + c = (b + r).reveal() + c_prime = c % two_to_m + a_prime = c_prime - r_prime + d = old_div((a - a_prime), two_to_m) + return d + +def SDiv(a, b, l, kappa): + theta = int(ceil(old_div(log(l / 3.5), log(2)))) + alpha = two_power(2*l) + beta = old_div(1, Compiler.types.cint(two_power(l))) + w = Compiler.types.cint(int(2.9142 * two_power(l))) - 2 * b + x = alpha - b * w + y = a * w + y = TruncPr(y, 2 * l, l, kappa) + x2 = Compiler.types.sint() + Compiler.comparison.Mod2m(x2, x, 2 * l + 1, l, kappa, False) + x1 = (x - x2) * beta + for i in range(theta-1): + y = y * (x1 + two_power(l)) + TruncPr(y * x2, 2 * l, l, kappa) + y = TruncPr(y, 2 * l + 1, l + 1, kappa) + x = x1 * x2 + TruncPr(x2**2, 2 * l + 1, l + 1, kappa) + x = x1 * x1 + TruncPr(x, 2 * l + 1, l - 1, kappa) + x2 = Compiler.types.sint() + Compiler.comparison.Mod2m(x2, x, 2 * l, l, kappa, False) + x1 = (x - x2) * beta + y = y * (x1 + two_power(l)) + TruncPr(y * x2, 2 * l, l, kappa) + y = TruncPr(y, 2 * l + 1, l - 1, kappa) + return y + +def SDiv_mono(a, b, l, kappa): + theta = int(ceil(old_div(log(l / 3.5), log(2)))) + alpha = two_power(2*l) + w = Compiler.types.cint(int(2.9142 * two_power(l))) - 2 * b + x = alpha - b * w + y = a * w + y = TruncPr(y, 2 * l + 1, l + 1, kappa) + for i in range(theta-1): + y = y * (alpha + x) + # keep y with l bits + y = TruncPr(y, 3 * l, 2 * l, kappa) + x = x**2 + # keep x with 2l bits + x = TruncPr(x, 4 * l, 2 * l, kappa) + y = y * (alpha + x) + y = TruncPr(y, 3 * l, 2 * l, kappa) + return y + +## +# SDiv as annotated in ABZS12. It perfroms +# division using rapson newton from approx on +# 2^l +def SDiv_ABZS12(a, b, l, kappa): + theta = int(ceil(log(l, 2))) + x = b + y = a + for i in range(theta -1): + y = y * ((2 ** (l + 1)) - x) + y = TruncPr(y, 2 * l + 1, l, kappa) + x = x * ((2 ** (l + 1)) - x) + x = TruncPr(x, 2 * l + 1, l, kappa) + y = y * ((2 ** (l + 1)) - x) + y = TruncPr(y, 2 * l + 1, l, kappa) + return y + +def AdditionKOp(a,b): + return a + b + + +def SolvedBits(x_bits, k): + pow_of_two= [x_bits[i] * 2 ** i for i in range(k)] + return KOpL(AdditionKOp, pow_of_two) diff --git a/Compiler/graph.py b/Compiler/graph.py index 0e5bc176..4710adb1 100644 --- a/Compiler/graph.py +++ b/Compiler/graph.py @@ -1,3 +1,7 @@ +from __future__ import print_function +from builtins import zip +from builtins import range +from builtins import object import heapq from Compiler.exceptions import * @@ -19,10 +23,10 @@ def __init__(self, max_nodes, default_attributes=None): if default_attributes is None: default_attributes = { 'merges': None, 'stop': -1, 'start': -1, 'is_source': True } self.default_attributes = default_attributes - self.attribute_pos = dict(zip(default_attributes.keys(), range(len(default_attributes)))) + self.attribute_pos = dict(list(zip(list(default_attributes.keys()), list(range(len(default_attributes)))))) self.n = max_nodes # each node contains list of default attributes, followed by outoing edges - self.nodes = [self.default_attributes.values() for i in range(self.n)] + self.nodes = [list(self.default_attributes.values()) for i in range(self.n)] self.pred = [[] for i in range(self.n)] self.weights = {} @@ -44,7 +48,7 @@ def add_node(self, i, **attr): raise CompilerError('Cannot add node %d to graph of size %d' % (i, self.n)) node = self.nodes[i] - for a,value in attr.items(): + for a,value in list(attr.items()): if a in self.default_attributes: node[self.attribute_pos[a]] = value else: @@ -73,7 +77,7 @@ def remove_node(self, i): #del self.weights[(v,i)] #self.nodes[v].remove(i) self.pred[i] = [] - self.nodes[i] = self.default_attributes.values() + self.nodes[i] = list(self.default_attributes.values()) def add_edge(self, i, j, weight=1): if j not in self[i]: @@ -113,7 +117,7 @@ def get_children(node): return G[node] else: def get_children(node): - if pref.has_key(node): + if node in pref: pref_set = set(pref[node]) for i in G[node]: if i not in pref_set: @@ -125,7 +129,7 @@ def get_children(node): yield i if nbunch is None: - nbunch = range(len(G)) + nbunch = list(range(len(G))) for v in nbunch: # process all vertices in G if v in explored: continue @@ -172,8 +176,8 @@ def reverse_dag_shortest_paths(G, source): dist[source] = 0 for u in top_order: if u ==68273: - print 'dist[68273]', dist[u] - print 'pred[u]', G.pred[u] + print('dist[68273]', dist[u]) + print('pred[u]', G.pred[u]) if dist[u] is None: continue for v in G.pred[u]: @@ -209,7 +213,7 @@ def longest_paths(G, sources=None): G.weights[edge] = -G.weights[edge] dist = {} for source in sources: - print ('%s, ' % source), + print(('%s, ' % source), end=' ') dist[source] = dag_shortest_paths(G, source) #dist = johnson(G, sources) # reset weights diff --git a/Compiler/gs.py b/Compiler/gs.py index 21d2d9d6..445a7d60 100644 --- a/Compiler/gs.py +++ b/Compiler/gs.py @@ -1,3 +1,8 @@ +from __future__ import print_function +from __future__ import division +from builtins import range +from past.utils import old_div +from builtins import object import sys import math @@ -29,9 +34,9 @@ def __setitem__(self, offset, item): def read(self, offset): return self.oram.read(self.get_index(offset)) -class OMatrix: +class OMatrix(object): def __init__(self, N, M=None, oram_type=OptimalORAM, int_type=types.sint): - print 'matrix', oram_type + print('matrix', oram_type) self.N = N self.M = M or N self.oram = oram_type(N * self.M, entry_size=log2(N), init_rounds=0, \ @@ -75,9 +80,9 @@ def __getitem__(self, a): def __setitem__(self, index, value): self.oram[index] = value -class OStack: +class OStack(object): def __init__(self, N, oram_type=OptimalORAM, int_type=types.sint): - print 'stack', oram_type + print('stack', oram_type) self.oram = oram_type(N, entry_size=log2(N), init_rounds=0, \ value_type=int_type.basic_type) self.size = types.MemValue(int_type(0)) @@ -89,14 +94,14 @@ def pop(self): self.size.isub(1) return self.oram[self.size] -class Matchmaker: +class Matchmaker(object): def init_hard(self, n_loops=None): if n_loops is None or n_loops > self.N * self.M: inner_loops = self.M outer_loops = self.N else: inner_loops = min(n_loops, self.M) - outer_loops = n_loops / inner_loops + outer_loops = old_div(n_loops, inner_loops) self.m_prefs = OMatrix(self.N, self.M, oram_type=self.oram_type, \ int_type=self.int_type) @for_range(outer_loops) @@ -201,7 +206,7 @@ def match(self, n_loops=None): init_rounds = self.N else: loop = for_range(n_loops) - init_rounds = n_loops / self.M + init_rounds = old_div(n_loops, self.M) self.wives = \ self.oram_type(self.N, entry_size=log2(self.N), \ init_rounds=0, value_type=self.basic_type) @@ -251,4 +256,4 @@ def __init__(self, N, M=None, reverse=False, oram_type=OptimalORAM, \ self.reverse = reverse self.int_type = int_type self.basic_type = int_type.basic_type - print 'match', self.oram_type + print('match', self.oram_type) diff --git a/Compiler/instructions.py b/Compiler/instructions.py index 3a828eba..756866e8 100644 --- a/Compiler/instructions.py +++ b/Compiler/instructions.py @@ -243,7 +243,7 @@ ##@instruction.py import itertools -import tools +from Compiler import tools from random import randint from Compiler.config import * from Compiler.exceptions import * @@ -263,8 +263,10 @@ class ldi(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['LDI'] - arg_format = ['cw', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDI'] + self.arg_format = ['cw', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -274,8 +276,10 @@ class ldsi(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['LDSI'] - arg_format = ['sw', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDSI'] + self.arg_format = ['sw', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) ## ##########################NEW OPCODES########################## @@ -289,8 +293,10 @@ class ldsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['LDSINT'] - arg_format = ['srw', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDSINT'] + self.arg_format = ['srw', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -300,8 +306,10 @@ class movsint(base.Instruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['MOVSINT'] - arg_format = ['srw', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MOVSINT'] + self.arg_format = ['srw', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -311,8 +319,10 @@ class opensint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['OPENSINT'] - arg_format = ['rw', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['OPENSINT'] + self.arg_format = ['rw', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -322,8 +332,10 @@ class opensbit(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['OPENSBIT'] - arg_format = ['rw', 'sb'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['OPENSBIT'] + self.arg_format = ['rw', 'sb'] + super(self.__class__, self).__init__(*args, **kwargs) #arithmetic opcodes @@ -334,8 +346,10 @@ class addsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ADDSINT'] - arg_format = ['srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ADDSINT'] + self.arg_format = ['srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class addsintc(base.Instruction): @@ -344,8 +358,10 @@ class addsintc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ADDSINTC'] - arg_format = ['srw', 'sr', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ADDSINTC'] + self.arg_format = ['srw', 'sr', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -355,8 +371,10 @@ class mulsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MULSINT'] - arg_format = ['srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MULSINT'] + self.arg_format = ['srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -366,8 +384,10 @@ class mulsintc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MULSINTC'] - arg_format = ['srw', 'sr', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MULSINTC'] + self.arg_format = ['srw', 'sr', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class mul2sint(base.Instruction): @@ -378,8 +398,10 @@ class mul2sint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MUL2SINT'] - arg_format = ['srw', 'srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MUL2SINT'] + self.arg_format = ['srw', 'srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) class GC(base.VarArgsInstruction): r""" GC i0, i1, i2, [srint_outputs], [srint_inputs] @@ -387,8 +409,8 @@ class GC(base.VarArgsInstruction): produces i1 srints as output, and takes i2 srints as input """ - code = base.opcodes['GC'] def __init__(self, *args): + self.code = base.opcodes['GC'] self.arg_format = ['int'] + ['int'] + ['int'] \ + ['srw'] * args[1] \ + ['sr'] * args[2] @@ -400,8 +422,8 @@ class LF_CINT(base.VarArgsInstruction): produces i1 cints as output, and takes i2 rints, i3 srints, i4 cints and i5 sints as input. """ - code = base.opcodes['LF_CINT'] def __init__(self, *args): + self.code = base.opcodes['LF_CINT'] self.arg_format = ['int'] + ['int'] \ + ['int'] + ['int'] + ['int'] + ['int'] \ + ['cw'] * args[1] \ @@ -418,8 +440,8 @@ class LF_SINT(base.VarArgsInstruction): produces i1 sints as output, and takes i2 rints, i3 srints, i4 cints and i5 sints as input. """ - code = base.opcodes['LF_SINT'] def __init__(self, *args): + self.code = base.opcodes['LF_SINT'] self.arg_format = ['int'] + ['int'] \ + ['int'] + ['int'] + ['int'] + ['int'] \ + ['sw'] * args[1] \ @@ -435,8 +457,8 @@ class LF_REGINT(base.VarArgsInstruction): produces i1 regints as output, and takes i2 rints, i3 srints, i4 cints and i5 sints as input. """ - code = base.opcodes['LF_REGINT'] def __init__(self, *args): + self.code = base.opcodes['LF_REGINT'] self.arg_format = ['int'] + ['int'] \ + ['int'] + ['int'] + ['int'] + ['int'] \ + ['rw'] * args[1] \ @@ -452,8 +474,8 @@ class LF_SREGINT(base.VarArgsInstruction): produces i1 sregints as output, and takes i2 rints, i3 srints, i4 cints and i5 sints as input. """ - code = base.opcodes['LF_SREGINT'] def __init__(self, *args): + self.code = base.opcodes['LF_SREGINT'] self.arg_format = ['int'] + ['int'] \ + ['int'] + ['int'] + ['int'] + ['int'] \ + ['srw'] * args[1] \ @@ -472,8 +494,10 @@ class subsintc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBSINTC'] - arg_format = ['srw', 'sr', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBSINTC'] + self.arg_format = ['srw', 'sr', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -483,8 +507,10 @@ class subsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBSINT'] - arg_format = ['srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBSINT'] + self.arg_format = ['srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -494,8 +520,10 @@ class subcints(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBCINTS'] - arg_format = ['srw', 'r', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBCINTS'] + self.arg_format = ['srw', 'r', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -505,8 +533,10 @@ class divsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['DIVSINT'] - arg_format = ['srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['DIVSINT'] + self.arg_format = ['srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class shlsint(base.Instruction): @@ -515,8 +545,10 @@ class shlsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SHLSINT'] - arg_format = ['srw', 'sr', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SHLSINT'] + self.arg_format = ['srw', 'sr', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class shrsint(base.Instruction): @@ -525,8 +557,10 @@ class shrsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SHRSINT'] - arg_format = ['srw', 'sr', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SHRSINT'] + self.arg_format = ['srw', 'sr', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -536,8 +570,10 @@ class neg(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['NEG'] - arg_format = ['srw', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['NEG'] + self.arg_format = ['srw', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) # Bitwise and Comparison opcodes @@ -548,8 +584,10 @@ class sand(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SAND'] - arg_format = ['srw', 'sr', 'sb'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SAND'] + self.arg_format = ['srw', 'sr', 'sb'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class andsint(base.Instruction): @@ -558,8 +596,10 @@ class andsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ANDSINT'] - arg_format = ['srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ANDSINT'] + self.arg_format = ['srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class andsintc(base.Instruction): @@ -568,8 +608,10 @@ class andsintc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ANDSINTC'] - arg_format = ['srw', 'sr', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ANDSINTC'] + self.arg_format = ['srw', 'sr', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class orsint(base.Instruction): @@ -578,8 +620,10 @@ class orsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ORSINT'] - arg_format = ['srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ORSINT'] + self.arg_format = ['srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class orsintc(base.Instruction): @@ -588,8 +632,10 @@ class orsintc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ORSINTC'] - arg_format = ['srw', 'sr', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ORSINTC'] + self.arg_format = ['srw', 'sr', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class xorsint(base.Instruction): @@ -598,8 +644,10 @@ class xorsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['XORSINT'] - arg_format = ['srw', 'sr', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['XORSINT'] + self.arg_format = ['srw', 'sr', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class xorsintc(base.Instruction): @@ -608,8 +656,10 @@ class xorsintc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['XORSINTC'] - arg_format = ['srw', 'sr', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['XORSINTC'] + self.arg_format = ['srw', 'sr', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class invsint(base.Instruction): @@ -618,8 +668,10 @@ class invsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['INVSINT'] - arg_format = ['srw', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['INVSINT'] + self.arg_format = ['srw', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) @@ -631,8 +683,10 @@ class xorsb(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sbw', 'sb', 'sb'] - code = base.opcodes['XORSB'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sbw', 'sb', 'sb'] + self.code = base.opcodes['XORSB'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -642,8 +696,10 @@ class andsb(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sbw', 'sb', 'sb'] - code = base.opcodes['ANDSB'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sbw', 'sb', 'sb'] + self.code = base.opcodes['ANDSB'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -653,8 +709,10 @@ class orsb(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sbw', 'sb', 'sb'] - code = base.opcodes['ORSB'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sbw', 'sb', 'sb'] + self.code = base.opcodes['ORSB'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -664,9 +722,10 @@ class negb(base.Instruction): This instruction is vectorizable """ __slots__ = [] - - arg_format = ['sbw', 'sb'] - code = base.opcodes['NEGB'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sbw', 'sb'] + self.code = base.opcodes['NEGB'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -676,8 +735,10 @@ class ltzsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sbw', 'sr'] - code = base.opcodes['LTZSINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sbw', 'sr'] + self.code = base.opcodes['LTZSINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -687,8 +748,10 @@ class eqzsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sbw', 'sr'] - code = base.opcodes['EQZSINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sbw', 'sr'] + self.code = base.opcodes['EQZSINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class bitsint(base.Instruction): @@ -697,8 +760,10 @@ class bitsint(base.Instruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['BITSINT'] - arg_format = ['sbw', 'sr', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['BITSINT'] + self.arg_format = ['sbw', 'sr', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class sintbit(base.Instruction): @@ -707,8 +772,10 @@ class sintbit(base.Instruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['SINTBIT'] - arg_format = ['srw', 'sr', 'sb', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SINTBIT'] + self.arg_format = ['srw', 'sr', 'sb', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @@ -720,8 +787,10 @@ class convsintsreg(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['CONVSINTSREG'] - arg_format = ['srw', 's'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CONVSINTSREG'] + self.arg_format = ['srw', 's'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -731,8 +800,10 @@ class convregsreg(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['CONVREGSREG'] - arg_format = ['srw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CONVREGSREG'] + self.arg_format = ['srw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -742,8 +813,10 @@ class convsregsint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['CONVSREGSINT'] - arg_format = ['sw', 'sr'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CONVSREGSINT'] + self.arg_format = ['sw', 'sr'] + super(self.__class__, self).__init__(*args, **kwargs) # memory instructions @@ -755,8 +828,10 @@ class ldmsint(base.DirectMemoryInstruction, base.ReadMemoryInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['LDMSINT'] - arg_format = ['srw', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMSINT'] + self.arg_format = ['srw', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -765,8 +840,10 @@ class ldmsinti(base.ReadMemoryInstruction): Assigns sregint register sr_i the value in sint memory SR[r_j], where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['LDMSINTI'] - arg_format = ['srw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMSINTI'] + self.arg_format = ['srw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -776,8 +853,10 @@ class stmsint(base.DirectMemoryWriteInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['STMSINT'] - arg_format = ['sr', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMSINT'] + self.arg_format = ['sr', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -786,8 +865,10 @@ class stmsinti(base.WriteMemoryInstruction): Sets sregint memory SR[r_j] to be the value in sregint register sr_i, where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['STMSINTI'] - arg_format = ['sr', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMSINTI'] + self.arg_format = ['sr', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) ## #########################END NEW OPCODES######################### @@ -798,8 +879,10 @@ class ldmc(base.DirectMemoryInstruction, base.ReadMemoryInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['LDMC'] - arg_format = ['cw', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMC'] + self.arg_format = ['cw', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -809,8 +892,10 @@ class ldms(base.DirectMemoryInstruction, base.ReadMemoryInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['LDMS'] - arg_format = ['sw', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMS'] + self.arg_format = ['sw', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -820,8 +905,10 @@ class stmc(base.DirectMemoryWriteInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['STMC'] - arg_format = ['c', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMC'] + self.arg_format = ['c', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -831,8 +918,10 @@ class stms(base.DirectMemoryWriteInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['STMS'] - arg_format = ['s', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMS'] + self.arg_format = ['s', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -842,8 +931,10 @@ class ldmint(base.DirectMemoryInstruction, base.ReadMemoryInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['LDMINT'] - arg_format = ['rw', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMINT'] + self.arg_format = ['rw', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -853,8 +944,10 @@ class stmint(base.DirectMemoryWriteInstruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['STMINT'] - arg_format = ['r', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMINT'] + self.arg_format = ['r', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) # must have seperate instructions because address is always modp @@ -864,8 +957,10 @@ class ldmci(base.ReadMemoryInstruction): Assigns cint register c_i the value in cint memory R[r_j], where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['LDMCI'] - arg_format = ['cw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMCI'] + self.arg_format = ['cw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -874,8 +969,10 @@ class ldmsi(base.ReadMemoryInstruction): Assigns sint register s_i the value in sint memory S[r_j], where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['LDMSI'] - arg_format = ['sw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMSI'] + self.arg_format = ['sw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -884,8 +981,10 @@ class stmci(base.WriteMemoryInstruction): Sets cint memory C[r_j] to be the value in cint register c_i, where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['STMCI'] - arg_format = ['c', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMCI'] + self.arg_format = ['c', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -894,8 +993,10 @@ class stmsi(base.WriteMemoryInstruction): Sets sint memory S[r_j] to be the value in sint register s_i, where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['STMSI'] - arg_format = ['s', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMSI'] + self.arg_format = ['s', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -904,8 +1005,10 @@ class ldminti(base.ReadMemoryInstruction): Assigns regint register r_i the value in memory R[r_j], where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['LDMINTI'] - arg_format = ['rw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDMINTI'] + self.arg_format = ['rw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -914,8 +1017,10 @@ class stminti(base.WriteMemoryInstruction): Sets regint memory R[r_j] to be the value in regint register r_i, where r_j is the j-th regint register. This instruction is vectorizable """ - code = base.opcodes['STMINTI'] - arg_format = ['r', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STMINTI'] + self.arg_format = ['r', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -925,8 +1030,10 @@ class movc(base.Instruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['MOVC'] - arg_format = ['cw', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MOVC'] + self.arg_format = ['cw', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -936,8 +1043,10 @@ class movs(base.Instruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['MOVS'] - arg_format = ['sw', 's'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MOVS'] + self.arg_format = ['sw', 's'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -947,8 +1056,10 @@ class movint(base.Instruction): This instruction is vectorizable """ __slots__ = ["code"] - code = base.opcodes['MOVINT'] - arg_format = ['rw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MOVINT'] + self.arg_format = ['rw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -957,8 +1068,10 @@ class pushint(base.StackInstruction): Pushes regint register r_i to the thread-local stack. This instruction is vectorizable """ - code = base.opcodes['PUSHINT'] - arg_format = ['r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PUSHINT'] + self.arg_format = ['r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -967,8 +1080,10 @@ class popint(base.StackInstruction): Pops from the thread-local stack to regint register r_i. This instruction is vectorizable """ - code = base.opcodes['POPINT'] - arg_format = ['rw'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['POPINT'] + self.arg_format = ['rw'] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -981,8 +1096,10 @@ class ldtn(base.Instruction): Assigns regint register r_i the number of the current thread. This instruction is vectorizable """ - code = base.opcodes['LDTN'] - arg_format = ['rw'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDTN'] + self.arg_format = ['rw'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -992,8 +1109,10 @@ class ldarg(base.Instruction): This is also used to pass variables to functions. This instruction is vectorizable """ - code = base.opcodes['LDARG'] - arg_format = ['rw'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDARG'] + self.arg_format = ['rw'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1003,16 +1122,20 @@ class starg(base.Instruction): This is also used to pass variables to functions. This instruction is vectorizable """ - code = base.opcodes['STARG'] - arg_format = ['r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STARG'] + self.arg_format = ['r'] + super(self.__class__, self).__init__(*args, **kwargs) class reqbl(base.Instruction): r""" REQBL n Signals tape has been built so that it requires prime bit length n". """ - code = base.opcodes['REQBL'] - arg_format = ['int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['REQBL'] + self.arg_format = ['int'] + super(self.__class__, self).__init__(*args, **kwargs) @@ -1020,32 +1143,40 @@ class run_tape(base.Instruction): r""" RUN_TAPE i j n In thread i start tape n with argument j. """ - code = base.opcodes['RUN_TAPE'] - arg_format = ['int', 'int', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['RUN_TAPE'] + self.arg_format = ['int', 'int', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) class join_tape(base.Instruction): r""" JOIN_TAPE i Wait until tape in thread i has finished. """ - code = base.opcodes['JOIN_TAPE'] - arg_format = ['int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['JOIN_TAPE'] + self.arg_format = ['int'] + super(self.__class__, self).__init__(*args, **kwargs) class crash(base.IOInstruction): r""" CRASH Crash the runtime by calling CRASH on the IO class. """ - code = base.opcodes['CRASH'] - arg_format = [] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CRASH'] + self.arg_format = [] + super(self.__class__, self).__init__(*args, **kwargs) class CALL(base.JumpInstruction): r""" CALL n Pushes the current PC onto the stack, and then performs an unconditional relative jump of n+1 instructions. """ __slots__ = [] - code = base.opcodes['CALL'] - arg_format = ['int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CALL'] + self.arg_format = ['int'] + super(self.__class__, self).__init__(*args, **kwargs) jump_arg = 0 class RETURN(base.JumpInstruction): @@ -1054,8 +1185,10 @@ class RETURN(base.JumpInstruction): to this value. Used to return from sub-routines executed by CALL """ - code = base.opcodes['RETURN'] - arg_format = [] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['RETURN'] + self.arg_format = [] + super(self.__class__, self).__init__(*args, **kwargs) jump_arg = -1 class restart(base.IOInstruction): @@ -1065,8 +1198,10 @@ class restart(base.IOInstruction): See the main documentation for how this instruction is intended to be used. This can only be called by thread zero, otherwise the runtime aborts. """ - code = base.opcodes['RESTART'] - arg_format = [] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['RESTART'] + self.arg_format = [] + super(self.__class__, self).__init__(*args, **kwargs) class clear_memory(base.WriteMemoryInstruction): r""" CLEAR_MEMORY @@ -1074,8 +1209,10 @@ class clear_memory(base.WriteMemoryInstruction): and the memory is still being used in another. It is really for usage in thread zero, when all other threads are doing nothing. Say before a RESTART """ - code = base.opcodes['CLEAR_MEMORY'] - arg_format = [] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CLEAR_MEMORY'] + self.arg_format = [] + super(self.__class__, self).__init__(*args, **kwargs) class clear_registers(base.IOInstruction): r""" CLEAR_REGISTERS @@ -1085,8 +1222,10 @@ class clear_registers(base.IOInstruction): some external users who are compiling their own byte-codes, so think of it as an experimental instruction. """ - code = base.opcodes['CLEAR_REGISTERS'] - arg_format = [] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CLEAR_REGISTERS'] + self.arg_format = [] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -1100,8 +1239,10 @@ class addc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ADDC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ADDC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1111,8 +1252,10 @@ class adds(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ADDS'] - arg_format = ['sw', 's', 's'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ADDS'] + self.arg_format = ['sw', 's', 's'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1122,8 +1265,10 @@ class addm(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ADDM'] - arg_format = ['sw', 's', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ADDM'] + self.arg_format = ['sw', 's', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1133,8 +1278,10 @@ class subc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1144,8 +1291,10 @@ class subs(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBS'] - arg_format = ['sw', 's', 's'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBS'] + self.arg_format = ['sw', 's', 's'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1155,8 +1304,10 @@ class subml(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBML'] - arg_format = ['sw', 's', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBML'] + self.arg_format = ['sw', 's', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1166,8 +1317,10 @@ class submr(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBMR'] - arg_format = ['sw', 'c', 's'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBMR'] + self.arg_format = ['sw', 'c', 's'] + super(self.__class__, self).__init__(*args, **kwargs) # Multiplication/division @@ -1178,8 +1331,10 @@ class mulc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MULC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MULC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1189,8 +1344,10 @@ class mulm(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MULM'] - arg_format = ['sw', 's', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MULM'] + self.arg_format = ['sw', 's', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1200,8 +1357,10 @@ class divc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['DIVC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['DIVC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1211,8 +1370,10 @@ class modc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MODC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MODC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1222,8 +1383,10 @@ class legendrec(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['LEGENDREC'] - arg_format = ['cw', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LEGENDREC'] + self.arg_format = ['cw', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1233,8 +1396,10 @@ class digestc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['DIGESTC'] - arg_format = ['cw', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['DIGESTC'] + self.arg_format = ['cw', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -1248,8 +1413,10 @@ class andc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ANDC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ANDC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1259,8 +1426,10 @@ class orc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ORC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ORC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1270,8 +1439,10 @@ class xorc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['XORC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['XORC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1281,8 +1452,10 @@ class notc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['NOTC'] - arg_format = ['cw', 'c', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['NOTC'] + self.arg_format = ['cw', 'c', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -1296,8 +1469,10 @@ class addci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ADDCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ADDCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__add__' @@ -1308,8 +1483,10 @@ class addsi(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ADDSI'] - arg_format = ['sw', 's', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ADDSI'] + self.arg_format = ['sw', 's', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__add__' @@ -1320,8 +1497,10 @@ class subci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__sub__' @@ -1332,8 +1511,10 @@ class subsi(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBSI'] - arg_format = ['sw', 's', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBSI'] + self.arg_format = ['sw', 's', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__sub__' @@ -1344,8 +1525,10 @@ class subcfi(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBCFI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBCFI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__rsub__' @@ -1356,8 +1539,10 @@ class subsfi(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SUBSFI'] - arg_format = ['sw', 's', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SUBSFI'] + self.arg_format = ['sw', 's', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__rsub__' @@ -1368,8 +1553,10 @@ class mulci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MULCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MULCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__mul__' @@ -1380,8 +1567,10 @@ class mulsi(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MULSI'] - arg_format = ['sw', 's', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MULSI'] + self.arg_format = ['sw', 's', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__mul__' @@ -1392,8 +1581,10 @@ class divci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['DIVCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['DIVCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1403,8 +1594,10 @@ class modci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['MODCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['MODCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__mod__' # Bitwise Operations with immediate values @@ -1416,8 +1609,10 @@ class andci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ANDCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ANDCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__and__' @@ -1428,8 +1623,10 @@ class xorci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['XORCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['XORCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__xor__' @@ -1440,8 +1637,10 @@ class orci(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['ORCI'] - arg_format = ['cw', 'c', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['ORCI'] + self.arg_format = ['cw', 'c', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__or__' @@ -1456,8 +1655,10 @@ class shlc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SHLC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SHLC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1467,8 +1668,10 @@ class shrc(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SHRC'] - arg_format = ['cw', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SHRC'] + self.arg_format = ['cw', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1478,7 +1681,9 @@ class shlci(base.ClearShiftInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SHLCI'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SHLCI'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__lshift__' @@ -1489,7 +1694,9 @@ class shrci(base.ClearShiftInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SHRCI'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SHRCI'] + super(self.__class__, self).__init__(*args, **kwargs) op = '__rshift__' @@ -1504,9 +1711,11 @@ class triple(base.DataInstruction): This instruction is vectorizable """ __slots__ = ['data_type'] - code = base.opcodes['TRIPLE'] - arg_format = ['sw', 'sw', 'sw'] - data_type = 'triple' + def __init__(self, *args, **kwargs): + self.code = base.opcodes['TRIPLE'] + self.arg_format = ['sw', 'sw', 'sw'] + self.data_type = 'triple' + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1516,8 +1725,10 @@ class bit(base.DataInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['BIT'] - arg_format = ['sw'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['BIT'] + self.arg_format = ['sw'] + super(self.__class__, self).__init__(*args, **kwargs) data_type = 'bit' @base.vectorize @@ -1527,8 +1738,10 @@ class dabit(base.DataInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['DABIT'] - arg_format = ['sw', 'sbw'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['DABIT'] + self.arg_format = ['sw', 'sbw'] + super(self.__class__, self).__init__(*args, **kwargs) data_type = 'dabit' @base.vectorize @@ -1538,8 +1751,10 @@ class square(base.DataInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['SQUARE'] - arg_format = ['sw', 'sw'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['SQUARE'] + self.arg_format = ['sw', 'sw'] + super(self.__class__, self).__init__(*args, **kwargs) data_type = 'square' @@ -1553,8 +1768,10 @@ class private_input(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['PRIVATE_INPUT'] - arg_format = ['sw', 'p','int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRIVATE_INPUT'] + self.arg_format = ['sw', 'p','int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1565,8 +1782,10 @@ class print_mem(base.IOInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['PRINT_MEM'] - arg_format = ['int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRINT_MEM'] + self.arg_format = ['int'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1577,8 +1796,10 @@ class print_reg(base.IOInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['PRINT_REG'] - arg_format = ['c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRINT_REG'] + self.arg_format = ['c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class print_fix(base.IOInstruction): @@ -1588,8 +1809,10 @@ class print_fix(base.IOInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['PRINT_FIX'] - arg_format = ['c', 'i', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRINT_FIX'] + self.arg_format = ['c', 'i', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class print_float(base.IOInstruction): @@ -1599,8 +1822,10 @@ class print_float(base.IOInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['PRINT_FLOAT'] - arg_format = ['c', 'c', 'c', 'c'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRINT_FLOAT'] + self.arg_format = ['c', 'c', 'c', 'c'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class print_int(base.IOInstruction): @@ -1610,8 +1835,10 @@ class print_int(base.IOInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['PRINT_INT'] - arg_format = ['r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRINT_INT'] + self.arg_format = ['r'] + super(self.__class__, self).__init__(*args, **kwargs) class print_char(base.IOInstruction): @@ -1620,10 +1847,9 @@ class print_char(base.IOInstruction): Can only be executed in thread zero. This instruction is vectorizable """ - code = base.opcodes['PRINT_CHAR'] - arg_format = ['int'] - def __init__(self, ch): + self.code = base.opcodes['PRINT_CHAR'] + self.arg_format = ['int'] super(print_char, self).__init__(ord(ch)) @@ -1633,10 +1859,9 @@ class print_char4(base.IOInstruction): Can only be executed in thread zero. This instruction is vectorizable """ - code = base.opcodes['PRINT_CHAR4'] - arg_format = ['int'] - def __init__(self, val): + self.code = base.opcodes['PRINT_CHAR4'] + self.arg_format = ['int'] super(print_char4, self).__init__(self.str_to_int(val)) @@ -1647,8 +1872,10 @@ class print_char_regint(base.IOInstruction): Can only be executed in thread zero. This instruction is vectorizable """ - code = base.opcodes['PRINT_CHAR_REGINT'] - arg_format = ['r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRINT_CHAR_REGINT'] + self.arg_format = ['r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class print_char4_regint(base.IOInstruction): @@ -1657,8 +1884,10 @@ class print_char4_regint(base.IOInstruction): Can only be executed in thread zero. This instruction is vectorizable """ - code = base.opcodes['PRINT_CHAR4_REGINT'] - arg_format = ['r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRINT_CHAR4_REGINT'] + self.arg_format = ['r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class input_clear(base.IOInstruction): @@ -1669,8 +1898,10 @@ class input_clear(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['INPUT_CLEAR'] - arg_format = ['cw','i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['INPUT_CLEAR'] + self.arg_format = ['cw','i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1682,8 +1913,10 @@ class input_int(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['INPUT_INT'] - arg_format = ['rw','i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['INPUT_INT'] + self.arg_format = ['rw','i'] + super(self.__class__, self).__init__(*args, **kwargs) class open_chan(base.IOInstruction): r""" OPEN_CHAN i n @@ -1694,8 +1927,10 @@ class open_chan(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['OPEN_CHAN'] - arg_format = ['rw','i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['OPEN_CHAN'] + self.arg_format = ['rw','i'] + super(self.__class__, self).__init__(*args, **kwargs) class close_channel(base.IOInstruction): r""" CLOSE_CHAN n @@ -1704,8 +1939,10 @@ class close_channel(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['CLOSE_CHAN'] - arg_format = ['i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CLOSE_CHAN'] + self.arg_format = ['i'] + super(self.__class__, self).__init__(*args, **kwargs) class output_shares(base.IOInstruction): @@ -1716,8 +1953,10 @@ class output_shares(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['OUTPUT_SHARE'] - arg_format = tools.chain(['i'],itertools.repeat('s')) + def __init__(self, *args, **kwargs): + self.code = base.opcodes['OUTPUT_SHARE'] + self.arg_format = tools.chain(['i'],itertools.repeat('s')) + super(self.__class__, self).__init__(*args, **kwargs) def has_var_args(self): return True @@ -1731,8 +1970,10 @@ class input_shares(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['INPUT_SHARE'] - arg_format = tools.chain(['i'],itertools.repeat('sw')) + def __init__(self, *args, **kwargs): + self.code = base.opcodes['INPUT_SHARE'] + self.arg_format = tools.chain(['i'],itertools.repeat('sw')) + super(self.__class__, self).__init__(*args, **kwargs) def has_var_args(self): return True @@ -1745,8 +1986,10 @@ class output_clear(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['OUTPUT_CLEAR'] - arg_format = ['c','i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['OUTPUT_CLEAR'] + self.arg_format = ['c','i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize class output_int(base.IOInstruction): @@ -1756,8 +1999,10 @@ class output_int(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['OUTPUT_INT'] - arg_format = ['r','i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['OUTPUT_INT'] + self.arg_format = ['r','i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1768,8 +2013,10 @@ class private_output(base.IOInstruction): Can only be executed in thread zero. """ __slots__ = [] - code = base.opcodes['PRIVATE_OUTPUT'] - arg_format = ['s', 'p', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['PRIVATE_OUTPUT'] + self.arg_format = ['s', 'p', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) # Others @@ -1780,8 +2027,10 @@ class rand(base.Instruction): The random value is the same for all players, so in particular it is not really random. """ __slots__ = [] - code = base.opcodes['RAND'] - arg_format = ['rw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['RAND'] + self.arg_format = ['rw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -1795,8 +2044,10 @@ class ldint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['LDINT'] - arg_format = ['rw', 'i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['LDINT'] + self.arg_format = ['rw', 'i'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1806,8 +2057,10 @@ class addint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r', 'r'] - code = base.opcodes['ADDINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r', 'r'] + self.code = base.opcodes['ADDINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1817,8 +2070,10 @@ class subint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r', 'r'] - code = base.opcodes['SUBINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r', 'r'] + self.code = base.opcodes['SUBINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1828,8 +2083,10 @@ class mulint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r', 'r'] - code = base.opcodes['MULINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r', 'r'] + self.code = base.opcodes['MULINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1839,8 +2096,10 @@ class divint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r', 'r'] - code = base.opcodes['DIVINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r', 'r'] + self.code = base.opcodes['DIVINT'] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -1854,8 +2113,10 @@ class eqzint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r'] - code = base.opcodes['EQZINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r'] + self.code = base.opcodes['EQZINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1865,8 +2126,10 @@ class ltzint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r'] - code = base.opcodes['LTZINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r'] + self.code = base.opcodes['LTZINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1876,8 +2139,10 @@ class ltint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r', 'r'] - code = base.opcodes['LTINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r', 'r'] + self.code = base.opcodes['LTINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1887,8 +2152,10 @@ class gtint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r', 'r'] - code = base.opcodes['GTINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r', 'r'] + self.code = base.opcodes['GTINT'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1898,8 +2165,10 @@ class eqint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - arg_format = ['rw', 'r', 'r'] - code = base.opcodes['EQINT'] + def __init__(self, *args, **kwargs): + self.arg_format = ['rw', 'r', 'r'] + self.code = base.opcodes['EQINT'] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -1911,8 +2180,10 @@ class jmp(base.JumpInstruction): Unconditional relative jump of n+1 instructions. """ __slots__ = [] - code = base.opcodes['JMP'] - arg_format = ['int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['JMP'] + self.arg_format = ['int'] + super(self.__class__, self).__init__(*args, **kwargs) jump_arg = 0 @@ -1925,8 +2196,10 @@ class jmpnz(base.JumpInstruction): jmpnz(c, -1): infinite loop if c is non-zero """ __slots__ = [] - code = base.opcodes['JMPNZ'] - arg_format = ['r', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['JMPNZ'] + self.arg_format = ['r', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) jump_arg = 1 @@ -1935,8 +2208,10 @@ class jmpeqz(base.JumpInstruction): Jump n+1 instructions if regint register r_i == 0. """ __slots__ = [] - code = base.opcodes['JMPEQZ'] - arg_format = ['r', 'int'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['JMPEQZ'] + self.arg_format = ['r', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) jump_arg = 1 @@ -1951,8 +2226,10 @@ class convint(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['CONVINT'] - arg_format = ['cw', 'r'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['CONVINT'] + self.arg_format = ['cw', 'r'] + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1963,11 +2240,11 @@ class convmodp(base.Instruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['CONVMODP'] - arg_format = ['rw', 'c', 'int'] def __init__(self, *args, **kwargs): bitlength = kwargs.get('bitlength', program.bit_length) + self.code = base.opcodes['CONVMODP'] + self.arg_format = ['rw', 'c', 'int'] super(convmodp_class, self).__init__(*(args + (bitlength,))) @@ -1982,8 +2259,10 @@ class startopen(base.VarArgsInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['STARTOPEN'] - arg_format = itertools.repeat('s') + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STARTOPEN'] + self.arg_format = itertools.repeat('s') + super(self.__class__, self).__init__(*args, **kwargs) @base.vectorize @@ -1993,23 +2272,29 @@ class stopopen(base.VarArgsInstruction): This instruction is vectorizable """ __slots__ = [] - code = base.opcodes['STOPOPEN'] - arg_format = itertools.repeat('cw') + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STOPOPEN'] + self.arg_format = itertools.repeat('cw') + super(self.__class__, self).__init__(*args, **kwargs) class start_clock(base.Instruction): r""" START_CLOCK n Re-initializes the specified timer n """ - code = base.opcodes['START_CLOCK'] - arg_format = ['i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['START_CLOCK'] + self.arg_format = ['i'] + super(self.__class__, self).__init__(*args, **kwargs) class stop_clock(base.Instruction): r""" STOP_CLOCK n Prints the time since the last initialization of timer n """ - code = base.opcodes['STOP_CLOCK'] - arg_format = ['i'] + def __init__(self, *args, **kwargs): + self.code = base.opcodes['STOP_CLOCK'] + self.arg_format = ['i'] + super(self.__class__, self).__init__(*args, **kwargs) # @@ -2023,7 +2308,9 @@ class asm_open(base.CISC): This instruction is vectorizable """ __slots__ = [] - arg_format = ['cw', 's'] + def __init__(self, *args, **kwargs): + self.arg_format = ['cw', 's'] + super(self.__class__, self).__init__(*args, **kwargs) def expand(self): startopen(self.args[1]) @@ -2036,7 +2323,9 @@ class muls(base.CISC): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sw', 's', 's'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sw', 's', 's'] + super(self.__class__, self).__init__(*args, **kwargs) def expand(self): s = [program.curr_block.new_reg('s') for i in range(9)] @@ -2060,7 +2349,9 @@ class sqrs(base.CISC): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sw', 's'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sw', 's'] + super(self.__class__, self).__init__(*args, **kwargs) def expand(self): s = [program.curr_block.new_reg('s') for i in range(6)] @@ -2081,7 +2372,9 @@ class lts(base.CISC): This instruction is vectorizable """ __slots__ = [] - arg_format = ['sw', 's', 's', 'int', 'int'] + def __init__(self, *args, **kwargs): + self.arg_format = ['sw', 's', 's', 'int', 'int'] + super(self.__class__, self).__init__(*args, **kwargs) def expand(self): a = program.curr_block.new_reg('s') @@ -2090,4 +2383,3 @@ def expand(self): # hack for circular dependency from Compiler import comparison - diff --git a/Compiler/instructions_base.py b/Compiler/instructions_base.py index 0f42096a..5fcac367 100644 --- a/Compiler/instructions_base.py +++ b/Compiler/instructions_base.py @@ -1,13 +1,23 @@ +from __future__ import print_function +from builtins import str +from builtins import zip +from builtins import object import itertools from random import randint import time import inspect import functools +import sys from Compiler.exceptions import * from Compiler.config import * from Compiler import util +if sys.version[0] == "3": + # If we're in python3, integers have unlimited size + long = int + + ### ### Opcode constants ### @@ -448,7 +458,7 @@ def __init__(self, *args, **kwargs): Instruction.count += 1 if Instruction.count % 100000 == 0: - print "Compiled %d lines at" % self.__class__.count, time.asctime() + print("Compiled %d lines at" % self.__class__.count, time.asctime()) def get_code(self): return self.code @@ -469,7 +479,7 @@ def get_bytes(self): def check_args(self): """ Check the args match up with that specified in arg_format """ - for n,(arg,f) in enumerate(itertools.izip_longest(self.args, self.arg_format)): + for n,(arg,f) in enumerate(itertools.zip_longest(self.args, self.arg_format)): if arg is None: if not isinstance(self.arg_format, (list, tuple)): break # end of optional arguments @@ -633,7 +643,7 @@ def set_relative_jump(self, value): def get_relative_jump(self): if self.jump_arg == -1: - return -1 + return -1 return self.args[self.jump_arg] diff --git a/Compiler/library.py b/Compiler/library.py index ddd930e1..f4675faa 100644 --- a/Compiler/library.py +++ b/Compiler/library.py @@ -1,3 +1,12 @@ +from __future__ import print_function +from __future__ import division +from future import standard_library +standard_library.install_aliases() +from builtins import zip +from builtins import str +from builtins import range +from past.utils import old_div +from builtins import object from Compiler.types import cint,sint,cfix,sfix,sfloat,cfloat,MPCThread,Array,MemValue,_number,_mem,_register,regint,Matrix,_types from Compiler.instructions import * from Compiler.util import tuplify,untuplify @@ -5,6 +14,11 @@ import inspect,math import random import collections +import sys + +if sys.version[0] == "3": + # If we're in python3, integers have unlimited size + long = int def get_program(): return instructions.program @@ -223,7 +237,7 @@ def make_array(l): return res -class FunctionTapeCall: +class FunctionTapeCall(object): def __init__(self, thread, base, bases): self.thread = thread self.base = base @@ -234,10 +248,10 @@ def start(self): def join(self): self.thread.join() instructions.program.free(self.base, 'r') - for reg_type,addr in self.bases.iteritems(): + for reg_type,addr in self.bases.items(): get_program().free(addr, reg_type.reg_type) -class Function: +class Function(object): def __init__(self, function, name=None, compile_args=[]): self.type_args = {} self.function = function @@ -258,7 +272,7 @@ def wrapped_function(*compile_args): bases = dict((t, regint.load_mem(base + i)) \ for i,t in enumerate(type_args)) runtime_args = [None] * len(args) - for t,i_args in type_args.iteritems(): + for t,i_args in type_args.items(): for i,i_arg in enumerate(i_args): runtime_args[i_arg] = t.load_mem(bases[t] + i) return self.function(*(list(compile_args) + runtime_args)) @@ -313,13 +327,13 @@ def on_first_call(self, wrapped_function): block.alloc_pool = defaultdict(set) del parent_node.children[-1] self.node = get_tape().req_node - print 'Compiling function', self.name + print('Compiling function', self.name) result = wrapped_function(*self.compile_args) if result is not None: self.result = memorize(result) else: self.result = None - print 'Done compiling function', self.name + print('Done compiling function', self.name) p_return_address = get_tape().program.malloc(1, 'r') get_tape().function_basicblocks[block] = p_return_address get_tape().active_basicblock.set_exit(instructions.RETURN(add_to_prog=False)) @@ -387,7 +401,7 @@ def sort(a): res = a for i in range(len(a)): - for j in reversed(range(i)): + for j in reversed(list(range(i))): res[j], res[j+1] = cond_swap(res[j], res[j+1]) return res @@ -401,7 +415,7 @@ def odd_even_merge(a): odd_even_merge(even) odd_even_merge(odd) a[0] = even[0] - for i in range(1, len(a) / 2): + for i in range(1, old_div(len(a), 2)): a[2*i-1], a[2*i] = cond_swap(odd[i-1], even[i]) a[-1] = odd[-1] @@ -409,8 +423,8 @@ def odd_even_merge_sort(a): if len(a) == 1: return elif len(a) % 2 == 0: - lower = a[:len(a)/2] - upper = a[len(a)/2:] + lower = a[:old_div(len(a),2)] + upper = a[old_div(len(a),2):] odd_even_merge_sort(lower) odd_even_merge_sort(upper) a[:] = lower + upper @@ -430,10 +444,10 @@ def chunky_odd_even_merge_sort(a): def round(): for i in range(len(a)): a[i] = type(a[i]).load_mem(i * a[i].sizeof()) - for i in range(len(a) / l): - for j in range(l / k): + for i in range(old_div(len(a), l)): + for j in range(old_div(l, k)): base = i * l + j - step = l / k + step = old_div(l, k) if k == 2: a[base], a[base+step] = cond_swap(a[base], a[base+step]) else: @@ -472,7 +486,7 @@ def run_threads(): def run_chunk(size, base): if size not in chunks: def swap_list(list_base): - for i in range(size / 2): + for i in range(old_div(size, 2)): base = list_base + 2 * i x, y = cond_swap(load_secret_mem(base), load_secret_mem(base + 1)) @@ -485,8 +499,8 @@ def swap_list(list_base): def run_round(size): # minimize number of chunk sizes n_chunks = int(math.ceil(1.0 * size / max_chunk_size)) - lower_size = size / n_chunks / 2 * 2 - n_lower_size = n_chunks - (size - n_chunks * lower_size) / 2 + lower_size = old_div(size, n_chunks / 2 * 2) + n_lower_size = n_chunks - old_div((size - n_chunks * lower_size), 2) # print len(to_swap) == lower_size * n_lower_size + \ # (lower_size + 2) * (n_chunks - n_lower_size), \ # len(to_swap), n_chunks, lower_size, n_lower_size @@ -562,10 +576,10 @@ def run_postproc(): k *= 2 size = 0 instructions.program.curr_tape.merge_opens = False - for i in range(n / l): - for j in range(l / k): + for i in range(old_div(n, l)): + for j in range(old_div(l, k)): base = i * l + j - step = l / k + step = old_div(l, k) size += run_setup(k, a_base + base, step, tmp_base + size) run_threads_in_rounds(pre_threads) run_round(size) @@ -610,7 +624,7 @@ def run_threads_in_rounds(all_threads): def run_chunk(size, base): if size not in chunks: def swap_list(list_base): - for i in range(size / 2): + for i in range(old_div(size, 2)): base = list_base + 2 * i x, y = cond_swap(load_secret_mem(base), load_secret_mem(base + 1)) @@ -623,8 +637,8 @@ def swap_list(list_base): def run_round(size): # minimize number of chunk sizes n_chunks = int(math.ceil(1.0 * size / max_chunk_size)) - lower_size = size / n_chunks / 2 * 2 - n_lower_size = n_chunks - (size - n_chunks * lower_size) / 2 + lower_size = old_div(size, n_chunks / 2 * 2) + n_lower_size = n_chunks - old_div((size - n_chunks * lower_size), 2) # print len(to_swap) == lower_size * n_lower_size + \ # (lower_size + 2) * (n_chunks - n_lower_size), \ # len(to_swap), n_chunks, lower_size, n_lower_size @@ -652,7 +666,7 @@ def load_and_store(x, y): def outer(i): def inner(j): base = j - step = l / k + step = old_div(l, k) if k == 2: tmp_addr = regint.load_mem(tmp_i) load_and_store(base, tmp_addr) @@ -664,19 +678,19 @@ def inner2(m): load_and_store(m, tmp_addr) store_in_mem(tmp_addr + 1, tmp_i) range_loop(inner2, base + step, base + (k - 1) * step, step) - range_loop(inner, a_base + i * l, a_base + i * l + l / k) + range_loop(inner, a_base + i * l, a_base + i * l + old_div(l, k)) instructions.program.curr_tape.merge_opens = False to_tmp = True store_in_mem(tmp_base, tmp_i) - range_loop(outer, n / l) + range_loop(outer, old_div(n, l)) if k == 2: run_round(n) else: - run_round(n / k * (k - 2)) + run_round(old_div(n, k * (k - 2))) instructions.program.curr_tape.merge_opens = False to_tmp = False store_in_mem(tmp_base, tmp_i) - range_loop(outer, n / l) + range_loop(outer, old_div(n, l)) if isinstance(a, list): instructions.program.restart_main_thread() @@ -694,15 +708,15 @@ def loopy_odd_even_merge_sort(a, sorted_length=1, n_parallel=32): k = 1 while k < l: k *= 2 - n_outer = len(a) / l - n_inner = l / k - n_innermost = 1 if k == 2 else k / 2 - 1 - @for_range_parallel(n_parallel / n_innermost / n_inner, n_outer) + n_outer = old_div(len(a), l) + n_inner = old_div(l, k) + n_innermost = 1 if k == 2 else old_div(k, 2) - 1 + @for_range_parallel(old_div(n_parallel, n_innermost / n_inner), n_outer) def loop(i): - @for_range_parallel(n_parallel / n_innermost, n_inner) + @for_range_parallel(old_div(n_parallel, n_innermost), n_inner) def inner(j): base = i*l + j - step = l/k + step = old_div(l,k) if k == 2: a[base], a[base+step] = cond_swap(a[base], a[base+step]) else: @@ -765,7 +779,7 @@ def loop_fn(i): # known loop count if condition(start): get_tape().req_node.children[-1].aggregator = \ - lambda x: ((stop - start) / step) * x[0] + lambda x: (old_div((stop - start), step)) * x[0] def for_range(start, stop=None, step=None): def decorator(loop_body): @@ -791,10 +805,10 @@ def map_reduce_single(n_parallel, n_loops, initializer, reducer, mem_state=None) use_array = True def decorator(loop_body): if isinstance(n_loops, int): - loop_rounds = n_loops / n_parallel \ + loop_rounds = old_div(n_loops, n_parallel) \ if n_parallel < n_loops else 0 else: - loop_rounds = n_loops / n_parallel + loop_rounds = old_div(n_loops, n_parallel) def write_state_to_memory(r): if use_array: mem_state.assign(r) @@ -846,7 +860,7 @@ def map_reduce(n_threads, n_parallel, n_loops, initializer, reducer, \ else: return dec def decorator(loop_body): - thread_rounds = n_loops / n_threads + thread_rounds = old_div(n_loops, n_threads) remainder = n_loops % n_threads for t in thread_mem_req: if t != regint: @@ -971,7 +985,7 @@ def do_while(loop_fn): return loop_fn def if_then(condition): - class State: pass + class State(object): pass state = State() if callable(condition): condition = condition() @@ -1134,7 +1148,7 @@ def test(value, lower=None, upper=None, prec=None): lineno *= 1000 store_in_mem(value, lineno + 1000) reg_type = 'c' - print "Test at", lineno + print("Test at", lineno) if lineno + 2000 > get_program().allocated_mem[reg_type]: get_program().allocated_mem[reg_type] = 2 * (lineno + 1000) @@ -1143,11 +1157,11 @@ def test1(value, lower=None, upper=None): value = reveal(value) lineno = inspect.currentframe().f_back.f_lineno stmc(value, lineno + 1000) - print "Test at", lineno + print("Test at", lineno) def test_mem(value, address, lower=None, upper=None): lineno = inspect.currentframe().f_back.f_lineno - print "Test at", lineno + print("Test at", lineno) def no_result_testing(): pass @@ -1155,7 +1169,7 @@ def no_result_testing(): # Fixed point ops from math import ceil, log -from floatingpoint import PreOR, TruncPr, two_power +from Compiler.floatingpoint import PreOR, TruncPr, two_power def approximate_reciprocal(divisor, k, f, theta): """ @@ -1222,7 +1236,7 @@ def cint_cint_division(a, b, k, f): # theta can be replaced with something smaller # for safety we assume that is the same theta from previous GS method - theta = int(ceil(log(k/3.5) / log(2))) + theta = int(ceil(old_div(log(k/3.5), log(2)))) two = cint(2) * two_power(f) sign_b = cint(1) - 2 * cint(b < 0) @@ -1250,7 +1264,7 @@ def sint_cint_division(a, b, k, f, kappa): """ type(a) = sint, type(b) = cint """ - theta = int(ceil(log(k/3.5) / log(2))) + theta = int(ceil(old_div(log(k/3.5), log(2)))) two = cint(2) * two_power(f) sign_b = cint(1) - 2 * cint(b < 0) sign_a = sint(1) - 2 * sint(a < 0) @@ -1279,7 +1293,7 @@ def FPDiv(a, b, k, f, kappa, simplex_flag=False): """ Goldschmidt method as presented in Catrina10, """ - theta = int(ceil(log(k/3.5) / log(2))) + theta = int(ceil(old_div(log(k/3.5), log(2)))) alpha = two_power(2*f) w = AppRcr(b, k, f, kappa, simplex_flag) x = alpha - b * w @@ -1380,7 +1394,7 @@ def int2FL_plain(a, gamma, l, kappa): blen = 0 for a_i in range(len(a_bits) - 1, -1, -1): # enumerate(a_bits): - b = (a_bits[a_i]) * (b == 0) * ((b_c) / 2) + b + b = (a_bits[a_i]) * (b == 0) * (old_div((b_c), 2)) + b blen = (a_bits[a_i]) * (blen == 0) * ((a_i + 1)) + blen b_c = b_c * 2 @@ -1396,7 +1410,7 @@ def int2FL_plain(a, gamma, l, kappa): if_then(a_abs > 0) if (lam > l): - v_l.write(v_l.read() / (2 ** (gamma - l - 1))) + v_l.write(old_div(v_l.read(), (2 ** (gamma - l - 1)))) else: v_l.write(v_l.read() * (2 ** l - lam)) diff --git a/Compiler/machine.py b/Compiler/machine.py index ab67fa87..2983d483 100644 --- a/Compiler/machine.py +++ b/Compiler/machine.py @@ -1,3 +1,6 @@ +from __future__ import print_function +from builtins import zip +from builtins import map from types import * from oram import * from path_oram import OptimalORAM @@ -55,7 +58,7 @@ def run_inst(inst_index, instructions, *args): for results in zip(*(op(*args) for op in instructions))) def run(code, data, operations, start=0, data_type=sint): - preops, postops, jumps = zip(*operations) + preops, postops, jumps = list(zip(*operations)) PC = MemValue(data_type(start)) tick = MemValue(cint(0)) @do_while @@ -102,7 +105,7 @@ def run_code_with_data(code, data, start=0, data_type=sint, oram_type=OptimalORA except ValueError: op = len(operations) if debug: - print op, inst[0] + print(op, inst[0]) operations.append(globals()[inst[0]]) inst[0] = 1 << op code.append((0, 0, 0, 0)) diff --git a/Compiler/mpc_math.py b/Compiler/mpc_math.py index 5d11d60b..da2b5eca 100644 --- a/Compiler/mpc_math.py +++ b/Compiler/mpc_math.py @@ -1,9 +1,12 @@ +from __future__ import division ## # @file # Arithmetic Module for Complex Math Operations # # Implements trigonometric and logarithmic functions. +from builtins import range +from past.utils import old_div import math from Compiler import floatingpoint from Compiler import types @@ -238,7 +241,7 @@ def tan(x): local_sin = ssin(w, b1) local_cos = scos(w, b2) # obtains the local tan - local_tan = local_sin/local_cos + local_tan = old_div(local_sin,local_cos) return local_tan @@ -259,7 +262,7 @@ def exp2_fx(a): # evaluates fractional part of a in p_1045 e = p_eval(p_1045, c) g = d * e - return (1 - s) * g + s * ((types.sfix(1)) / g) + return (1 - s) * g + s * (old_div((types.sfix(1)), g)) ## @@ -286,7 +289,7 @@ def log2_fx(x): P = p_eval(p_2524, v) Q = p_eval(q_2524, v) # the log is returned by adding the result of the division plus p. - a = P / Q + load_sint(d.vlen + d.p, type(x)) + a = old_div(P, Q) + load_sint(d.vlen + d.p, type(x)) return a # *(1-(f.z))*(1-f.s)*(1-f.error) @@ -418,7 +421,7 @@ def norm_simplified_SQ(b, k): m_odd = m_odd + z[i] # construct w, - k_over_2 = k / 2 + 1 + k_over_2 = old_div(k, 2) + 1 w_array = [0] * (k_over_2) w_array[0] = z[0] for i in range(1, k_over_2): @@ -452,11 +455,11 @@ def sqrt_simplified_fx(x): m_odd = (1 - 2 * m_odd) * ( x.f % 2) + m_odd w = (w * 2 - w) * (1-m_odd) * (x.f % 2) + w # map number to use sfix format and instantiate the number - w = types.sfix(w * 2 ** ((x.f - (x.f % 2)) / 2)) + w = types.sfix(w * 2 ** (old_div((x.f - (x.f % 2)), 2))) # obtains correct 2 ** (m/2) w = (w * (types.cfix(2 ** (1/2.0))) - w) * m_odd + w # produce x/ 2^(m/2) - y_0 = types.cfix(1.0) / w + y_0 = old_div(types.cfix(1.0), w) # from this point on it sufices to work sfix-wise g_0 = (y_0 * x) @@ -513,7 +516,7 @@ def norm_SQ(b, k): # construct w, changes from what is on the paper # and the documentation - k_over_2= k/2+1#int(math.ceil((k/2.0)))+1 + k_over_2= old_div(k,2)+1#int(math.ceil((k/2.0)))+1 w_array = [0]*(k_over_2 ) w_array[0] = z[0] for i in range(1, k_over_2): @@ -647,14 +650,14 @@ def atan(x): x_abs = (s * (-2) + 1) * x # angle isolation b = x_abs > 1 - v = (types.cfix(1.0) / x_abs) + v = (old_div(types.cfix(1.0), x_abs)) v = (1 - b) * (x_abs - v) + v v_2 =v*v P = p_eval(p_5102, v_2) Q = p_eval(q_5102, v_2) # padding - y = v * (P / Q) + y = v * (old_div(P, Q)) y_pi_over_two = pi_over_2 - y # sign correction @@ -675,7 +678,7 @@ def asin(x): x_2 = x*x # trignometric identities sqrt_l = sqrt(1- (x_2)) - x_sqrt_l =x / sqrt_l + x_sqrt_l =old_div(x, sqrt_l) return atan(x_sqrt_l) diff --git a/Compiler/oram.py b/Compiler/oram.py index 093e26b8..ad9b608a 100644 --- a/Compiler/oram.py +++ b/Compiler/oram.py @@ -1,19 +1,35 @@ +from __future__ import print_function +from __future__ import division +from builtins import next +from builtins import map +from builtins import str +from builtins import zip +from builtins import range +from past.utils import old_div +from builtins import object import random import math import collections import itertools import operator import sys +from functools import reduce + + +if sys.version[0] == "3": + # If we're in python3, integers have unlimited size + long = int + if 'Emulation' in sys.path: - print 'emulation mode' + print('emulation mode') from Emulation.library import * from Emulation.types import * from Emulation.types import _secret from Emulation.program import Program from Emulation import floatingpoint,comparison,permutation else: - print 'compilation mode' + print('compilation mode') from Compiler.types import * from Compiler.types import _secret from Compiler.library import * @@ -68,7 +84,7 @@ def __init__(self, value, start, lengths, entries_per_block): self.lower, self.shift = \ floatingpoint.Trunc(self.value, self.n_bits, self.start, \ Program.prog.security, True) - trunc = (self.value - self.lower) / self.shift + trunc = old_div((self.value - self.lower), self.shift) self.slice = trunc.mod2m(length, self.n_bits, False) self.upper = (trunc - self.slice) * self.shift def get_slice(self): @@ -104,7 +120,7 @@ def __init__(self, value, start, lengths, entries_per_block): prod_bits = [start * bit for bit in value_bits] anti_bits = [v - p for v,p in zip(value_bits,prod_bits)] self.lower = sum(bit << i for i,bit in enumerate(prod_bits[:length])) - self.bits = map(operator.add, anti_bits[:length], prod_bits[length:]) + \ + self.bits = list(map(operator.add, anti_bits[:length], prod_bits[length:])) + \ anti_bits[length:] self.adjust = if_else(start, 1 << length, cgf2n(1)) elif entries_per_block < 4: @@ -114,7 +130,7 @@ def __init__(self, value, start, lengths, entries_per_block): choice_bits = demux(start_bits) inv_bits = [1 - bit for bit in floatingpoint.PreOR(choice_bits, None)] mask_bits = sum(([x] * length for x in inv_bits), []) - lower_bits = map(operator.mul, value_bits, mask_bits) + lower_bits = list(map(operator.mul, value_bits, mask_bits)) self.lower = sum(bit << i for i,bit in enumerate(lower_bits)) self.bits = [sum(map(operator.mul, choice_bits, value_bits[i::length])) \ for i in range(length)] @@ -133,10 +149,10 @@ def __init__(self, value, start, lengths, entries_per_block): pre_bits = floatingpoint.PreOpL(lambda x,y,z=None: x + y, bits) inv_bits = [1 - bit for bit in pre_bits] mask_bits = sum(([x] * length for x in inv_bits), []) - lower_bits = map(operator.mul, value_bits, mask_bits) + lower_bits = list(map(operator.mul, value_bits, mask_bits)) masked = self.value - sum(bit << i for i,bit in enumerate(lower_bits)) self.lower = sum(bit << i for i,bit in enumerate(lower_bits)) - self.bits = (masked / adjust).bit_decompose(used_bits) + self.bits = (old_div(masked, adjust)).bit_decompose(used_bits) self.adjust = adjust Program.prog.curr_tape.\ start_new_basicblock(name='gf2n-block-init-end-%d' % entries_per_block) @@ -186,12 +202,12 @@ def demux_list(x): return [1] elif n == 1: return [1 - x[0], x[0]] - a = demux_list(x[:n/2]) - b = demux_list(x[n/2:]) + a = demux_list(x[:old_div(n,2)]) + b = demux_list(x[old_div(n,2):]) n_a = len(a) a *= len(b) b = reduce(operator.add, ([i] * n_a for i in b)) - res = map(operator.mul, a, b) + res = list(map(operator.mul, a, b)) return res def demux_array(x): @@ -201,12 +217,12 @@ def demux_array(x): res[0] = 1 - x[0] res[1] = x[0] else: - a = Array(2**(n/2), type(x[0])) - a.assign(demux(x[:n/2])) - b = Array(2**(n-n/2), type(x[0])) - b.assign(demux(x[n/2:])) + a = Array(2**(old_div(n,2)), type(x[0])) + a.assign(demux(x[:old_div(n,2)])) + b = Array(2**(n-old_div(n,2)), type(x[0])) + b.assign(demux(x[old_div(n,2):])) @for_range_multithread(get_n_threads(len(res)), \ - max(1, n_parallel / len(b)), len(a)) + max(1, old_div(n_parallel, len(b))), len(a)) def f(i): @for_range_parallel(n_parallel, len(b)) def f(j): @@ -260,9 +276,9 @@ def __repr__(self): try: value = self.empty while True: - if value in (1, 1L): + if value == 1: return '<>' - if value in (0, 0L): + if value == 0: return '<%s>' % str(self.value) value = value.value except: @@ -297,8 +313,8 @@ def __init__(self, v, x=None, empty=None, value_type=None): self.created_non_empty = False if x is None: v = iter(v) - self.is_empty = v.next() - self.v = v.next() + self.is_empty = next(v) + self.v = next(v) self.x = ValueTuple(v) else: if empty is None: @@ -332,7 +348,7 @@ def __add__(self, other): try: return Entry(i + j for i,j in zip(self, other)) except: - print self, other + print(self, other) raise def __sub__(self, other): return Entry(i - j for i,j in zip(self, other)) @@ -342,7 +358,7 @@ def __mul__(self, other): try: return Entry(other * i for i in self) except: - print self, other + print(self, other) raise __rmul__ = __mul__ def reveal(self): @@ -372,8 +388,8 @@ def f(): for t,array in zip(self.entry_type,oram.ram.l)] self.index = index def init_mem(self, empty_entry): - print 'init ram' - for a,value in zip(self.l, empty_entry.values()): + print('init ram') + for a,value in zip(self.l, list(empty_entry.values())): a.assign_all(value) def get_empty_bits(self): return self.l[0] @@ -391,14 +407,14 @@ def get_value_array(self, index): return [Value(self.l[2+index][i], self.l[0][i]) for i in range(self.size)] def __getitem__(self, index): if print_access: - print 'get', id(self), index + print('get', id(self), index) return Entry(a[index] for a in self.l) def __setitem__(self, index, value): if print_access: - print 'set', id(self), index + print('set', id(self), index) if not isinstance(value, Entry): raise Exception('entries only please: %s' % str(value)) - for i,(a,v) in enumerate(zip(self.l, value.values())): + for i,(a,v) in enumerate(zip(self.l, list(value.values()))): a[index] = v def __len__(self): return self.size @@ -508,7 +524,7 @@ def __init__(self, index, oram): self.value_type, self.value_length = oram.internal_value_type() self.size = oram.bucket_size def init_mem(self): - print 'init trivial oram' + print('init trivial oram') self.ram.init_mem(self.empty_entry()) def search(self, read_index): if use_binary_search and self.value_type == sgf2n: @@ -538,7 +554,7 @@ def read_and_remove(self, read_index, skip=0): self.last_index = read_index found, empty = self.search(read_index) entries = [entry for entry in self.ram] - prod_entries = map(operator.mul, found, entries) + prod_entries = list(map(operator.mul, found, entries)) read_value = sum((entry.x.skip(skip) for entry in prod_entries), \ empty * empty_entry.x.skip(skip)) for i,(entry, prod_entry) in enumerate(zip(entries, prod_entries)): @@ -550,7 +566,7 @@ def read_and_maybe_remove(self, index): def read_and_remove_by_public(self, index): empty_entry = self.empty_entry(False) entries = [entry for entry in self.ram] - prod_entries = map(operator.mul, index, entries) + prod_entries = list(map(operator.mul, index, entries)) read_entry = reduce(operator.add, prod_entries) for i,(entry, prod_entry) in enumerate(zip(entries, prod_entries)): self.ram[i] = entry - prod_entry + index[i] * empty_entry @@ -558,7 +574,7 @@ def read_and_remove_by_public(self, index): @method_block def _read(self, index): found, empty = self.search(index) - read_value = sum(map(operator.mul, found, self.ram.get_values()), \ + read_value = sum(list(map(operator.mul, found, self.ram.get_values())), \ empty * self.empty_entry(False).x) return read_value, empty @method_block @@ -567,8 +583,8 @@ def _access(self, index, write, new_empty, *new_value): found, not_found = self.search(index) add_here = self.find_first_empty() entries = [entry for entry in self.ram] - prod_values = map(operator.mul, found, \ - (entry.x for entry in entries)) + prod_values = list(map(operator.mul, found, \ + (entry.x for entry in entries))) read_value = sum(prod_values, not_found * empty_entry.x) new_value = ValueTuple(new_value) \ if isinstance(new_value, (tuple, list)) \ @@ -683,15 +699,15 @@ def binary_search(self, index): for k in range(2**(j)): t = k + 2**(j) - 1 if k % 2 == 0: - M += bit_prods[(t-1)/2] * mult_tree[t] + M += bit_prods[old_div((t-1),2)] * mult_tree[t] b = 1 - M.equal(0, 40, expand) for k in range(2**j): t = k + 2**j - 1 if k % 2 == 0: - v = bit_prods[(t-1)/2] * b - bit_prods[t] = bit_prods[(t-1)/2] - v + v = bit_prods[old_div((t-1),2)] * b + bit_prods[t] = bit_prods[old_div((t-1),2)] - v else: bit_prods[t] = v return bit_prods[n-1:n-1+self.size], 1 - bit_prods[0] @@ -718,7 +734,7 @@ def f(): print_ln('Bucket overflow') crash() if debug and not sum(add_here) and not new_entry.empty(): - print self.empty_entry() + print(self.empty_entry()) raise Exception('no space for %s in %s' % (str(new_entry), str(self))) self.check(new_entry=new_entry, op='add') def pop(self): @@ -730,7 +746,7 @@ def pop(self): pop_here = [prefix_empty[i+1] - prefix_empty[i] \ for i in range(len(self.ram))] entries = [entry for entry in self.ram] - prod_entries = map(operator.mul, pop_here, self.ram) + prod_entries = list(map(operator.mul, pop_here, self.ram)) result = (1 - sum(pop_here)) * empty_entry result = sum(prod_entries, result) for i,(entry, prod_entry) in enumerate(zip(entries, prod_entries)): @@ -945,7 +961,7 @@ def __init__(self, size, entry_size, value_type=sint, init_rounds=-1, \ @for_range(init_rounds if init_rounds > 0 else size) def f(i): self.l[0][i] = random_block(entry_size, value_type) - print 'index size:', size + print('index size:', size) def update(self, index, value): read_value = self[index] #print 'read', index, read_value @@ -970,17 +986,17 @@ class TreeORAM(AbstractORAM): """ Tree ORAM. """ def __init__(self, size, value_type=sint, value_length=1, entry_size=None, \ bucket_oram=TrivialORAM, init_rounds=-1): - print 'create oram of size', size + print('create oram of size', size) self.bucket_oram = bucket_oram # heuristic bucket size delta = 3 - k = (math.log(size * size * log2(size) * 100, 2) + 21) / (1 + delta) + k = old_div((math.log(size * size * log2(size) * 100, 2) + 21), (1 + delta)) # size + 1 for bucket overflow check self.bucket_size = min(int(math.ceil((1 + delta) * k)), size + 1) - self.D = log2(max(size / k, 2)) - print 'bucket size:', self.bucket_size - print 'depth:', self.D - print 'complexity:', self.bucket_size * (self.D + 1) + self.D = log2(max(old_div(size, k), 2)) + print('bucket size:', self.bucket_size) + print('depth:', self.D) + print('complexity:', self.bucket_size * (self.D + 1)) self.value_type = value_type if entry_size is not None: self.value_length = len(tuplify(entry_size)) @@ -1233,8 +1249,8 @@ def batch_init(self, values): # split into 2 if bucket size can't fit into one field elem if self.bucket_size + Program.prog.security > 128: parity = (empty_positions[i]+1) % 2 - half = (empty_positions[i]+1 - parity) / 2 - half_max = self.bucket_size / 2 + half = old_div((empty_positions[i]+1 - parity), 2) + half_max = old_div(self.bucket_size, 2) bits = floatingpoint.B2U(half, half_max, Program.prog.security)[0] bits2 = floatingpoint.B2U(half+parity, half_max, Program.prog.security)[0] @@ -1336,12 +1352,12 @@ def get_parallel(index_size, value_type, value_length): value_size = get_value_size(value_type) if value_type == sint: value_size *= 2 - res = max(1, min(50 * 32 / (value_length * value_size), \ - 800 * 32 / (value_length * index_size))) + res = max(1, min(old_div(50 * 32, (value_length * value_size)), \ + old_div(800 * 32, (value_length * index_size)))) if comparison.const_rounds: - res = max(1, res / 2) + res = max(1, old_div(res, 2)) if 'Emulation' not in sys.path: - print 'Reading %d buckets in parallel' % res + print('Reading %d buckets in parallel' % res) return res class PackedIndexStructure(object): @@ -1376,24 +1392,24 @@ def __init__(self, size, entry_size=None, value_type=sint, init_rounds=-1, \ self.elements_per_entry = len(self.split_sizes) self.log_elements_per_block = log2(self.elements_per_entry) self.log_entries_per_element = -self.log_elements_per_block - print 'split sizes:', self.split_sizes + print('split sizes:', self.split_sizes) self.log_entries_per_block = \ self.log_elements_per_block + self.log_entries_per_element self.elements_per_block = 2**self.log_elements_per_block self.entries_per_element = 2**self.log_entries_per_element self.entries_per_block = 2**self.log_entries_per_block self.used_bits = self.entries_per_element * sum(self.entry_size) - real_size = -(-size / self.entries_per_block) - print 'packed size:', real_size - print 'index size:', size - print 'entry size:', self.entry_size - print 'log(entries per element):', self.log_entries_per_element - print 'entries per element:', self.entries_per_element - print 'log(entries per block):', self.log_entries_per_block - print 'entries per block:', self.entries_per_block - print 'log(elements per block):', self.log_elements_per_block - print 'elements per block:', self.elements_per_block - print 'used bits:', self.used_bits + real_size = -(old_div(-size, self.entries_per_block)) + print('packed size:', real_size) + print('index size:', size) + print('entry size:', self.entry_size) + print('log(entries per element):', self.log_entries_per_element) + print('entries per element:', self.entries_per_element) + print('log(entries per block):', self.log_entries_per_block) + print('entries per block:', self.entries_per_block) + print('log(elements per block):', self.log_elements_per_block) + print('elements per block:', self.elements_per_block) + print('used bits:', self.used_bits) if real_size > 1: # no need to init underlying ORAM, will be initialized implicitely self.l = self.storage(real_size, value_type, self.elements_per_block, \ @@ -1404,10 +1420,10 @@ def __init__(self, size, entry_size=None, value_type=sint, init_rounds=-1, \ self.small = True if init_rounds: if init_rounds > 0: - real_init_rounds = init_rounds * real_size / size + real_init_rounds = old_div(init_rounds * real_size, size) else: real_init_rounds = real_size - print 'packed init rounds:', real_init_rounds + print('packed init rounds:', real_init_rounds) @for_range(real_init_rounds) def f(i): if random_init: @@ -1417,7 +1433,7 @@ def f(i): self.l[i] = [0] * self.elements_per_block time() print_ln('packed ORAM init %s/%s', i, real_init_rounds) - print 'index initialized, size', size + print('index initialized, size', size) def translate_index(self, index): """ Bit slicing *index* according parameters. Output is tuple (storage address, index with storage cell, index within @@ -1426,11 +1442,11 @@ def translate_index(self, index): rem = mod2m(index, self.log_entries_per_block, log2(self.size), False) c = mod2m(rem, self.log_entries_per_element, \ self.log_entries_per_block, False) - b = (rem - c) / self.entries_per_element + b = old_div((rem - c), self.entries_per_element) if self.small: return 0, b, c else: - return (index - rem) / self.entries_per_block, b, c + return old_div((index - rem), self.entries_per_block), b, c else: index_bits = bit_decompose(index, log2(self.size)) l1 = self.log_entries_per_element @@ -1451,16 +1467,16 @@ def read(self, block): self.block = block self.index_vector = \ demux(bit_decompose(self.b, self.pack.log_elements_per_block)) - self.vector = map(operator.mul, self.index_vector, block) + self.vector = list(map(operator.mul, self.index_vector, block)) self.element = get_block(sum(self.vector), self.c, \ self.pack.entry_size, \ self.pack.entries_per_element) return tuple(self.element.get_slice()) def write(self, value): self.element.set_slice(value) - anti_vector = map(operator.sub, self.block, self.vector) + anti_vector = list(map(operator.sub, self.block, self.vector)) updated_vector = [self.element.value * i for i in self.index_vector] - updated_block = map(operator.add, anti_vector, updated_vector) + updated_block = list(map(operator.add, anti_vector, updated_vector)) return updated_block class MultiSlicer(object): def __init__(self, pack, index): @@ -1518,7 +1534,7 @@ def __setitem__(self, index, value): def batch_init(self, values): """ Initialize m values with indices 0, ..., m-1 """ m = len(values) - n_entries = max(1, m/self.entries_per_block) + n_entries = max(1, old_div(m,self.entries_per_block)) new_values = [0] * n_entries for i in range(n_entries): @@ -1628,7 +1644,7 @@ class OptimalPackedORAMWithEmpty(PackedORAMWithEmpty): def test_oram(oram_type, N, value_type=sint, iterations=100): oram = oram_type(N, value_type=value_type, entry_size=32, init_rounds=0) - print 'initialized' + print('initialized') print_ln('initialized') stop_timer() # synchronize @@ -1656,7 +1672,7 @@ def f(i): def test_oram_access(oram_type, N, value_type=sint, index_size=None, iterations=100): oram = oram_type(N, value_type=value_type, entry_size=32, \ init_rounds=0) - print 'initialized' + print('initialized') print_reg_char4(cint(0), 'init') stop_timer() # synchronize @@ -1669,11 +1685,11 @@ def test_oram_access(oram_type, N, value_type=sint, index_size=None, iterations= def f(i): oram.access(value_type(i % N), value_type(0), value_type(True)) oram.access(value_type(i % N), value_type(i % N), value_type(True)) - print 'first write' + print('first write') time() x = oram.access(value_type(i % N), value_type(0), value_type(False)) x[0][0].reveal().print_reg('writ') - print 'first read' + print('first read') # @for_range(iterations) # def f(i): # x = oram.access(value_type(i % N), value_type(0), value_type(False), \ @@ -1685,7 +1701,7 @@ def f(i): def test_batch_init(oram_type, N): value_type = sint oram = oram_type(N, value_type) - print 'initialized' + print('initialized') print_reg_char4(cint(0), 'init') oram.batch_init([value_type(i) for i in range(N)]) print_reg_char4(cint(0), 'done') diff --git a/Compiler/path_oram.py b/Compiler/path_oram.py index 9d6ff724..bc19f3ad 100644 --- a/Compiler/path_oram.py +++ b/Compiler/path_oram.py @@ -1,3 +1,11 @@ +from __future__ import print_function +from __future__ import division +from builtins import map +from builtins import zip +from builtins import range +from builtins import object +from past.utils import old_div +from functools import reduce if '_Array' not in dir(): from oram import * import permutation @@ -43,7 +51,7 @@ def increment(self, b): def decrement(self, b): """ Decrement counter by a secret bit """ if self.value_type is sgf2n: - inv_2 = cgf2n(1) / cgf2n(2) + inv_2 = old_div(cgf2n(1), cgf2n(2)) prod = self.value * b self.value = (inv_2*prod + self.value - prod) self._used = True @@ -102,7 +110,7 @@ def bucket_size_sorter(x, y): Z = len(x) - 1 xs = x[-1] ys = y[-1] - t = 2**Z * xs / ys + t = old_div(2**Z * xs, ys) # xs <= yx if bits 0 to Z of t are 0 return 1 - reduce(lambda x,y: x*y, t.bit_decompose(2*Z)[:Z]) @@ -138,7 +146,7 @@ def __init__(self, size, value_type=sgf2n, value_length=1, entry_size=None, \ bucket_size=2, init_rounds=-1): #if size <= k: # raise CompilerError('ORAM size too small') - print 'create oram of size', size + print('create oram of size', size) self.bucket_oram = bucket_oram self.bucket_size = bucket_size self.D = log2(size) @@ -234,7 +242,7 @@ def evict(): self.state.write(self.value_type(leaf)) - print 'eviction leaf =', leaf + print('eviction leaf =', leaf) # load the path for i, ram_indices in enumerate(self.bucket_indices_on_path_to(leaf)): @@ -318,7 +326,7 @@ def read_and_remove_levels(self, u): # at most one 1 in found empty = 1 - sum(found) - prod_entries = map(operator.mul, found, entries) + prod_entries = list(map(operator.mul, found, entries)) read_value = sum((entry.x.skip(skip) for entry in prod_entries), \ empty * empty_entry.x.skip(skip)) for i,(j, entry, prod_entry) in enumerate(zip(ram_indices, entries, prod_entries)): @@ -521,7 +529,7 @@ def read_and_remove(self, u): values = (ValueTuple(x) for x in zip(*self.read_value)) not_empty = [1 - x for x in self.read_empty] read_empty = 1 - sum(not_empty) - read_value = sum(map(operator.mul, not_empty, values), \ + read_value = sum(list(map(operator.mul, not_empty, values)), \ ValueTuple(0 for i in range(self.value_length))) self.check(u) Program.prog.curr_tape.\ @@ -538,7 +546,7 @@ def buckets_on_path_to(self, leaf): yield bucket def bucket_indices_on_path_to(self, leaf): leaf = regint(leaf) - yield range(self.bucket_size) + yield list(range(self.bucket_size)) index = 0 for i in range(self.D): index = 2*index + 1 + regint(cint(leaf) & 1) @@ -735,7 +743,7 @@ def add(self, entry, state=None): try: self.stash.add(e) except Exception: - print self + print(self) raise self.evict() diff --git a/Compiler/permutation.py b/Compiler/permutation.py index 4f245e49..462ac198 100644 --- a/Compiler/permutation.py +++ b/Compiler/permutation.py @@ -1,3 +1,8 @@ +from __future__ import division +from builtins import next +from builtins import zip +from builtins import range +from past.utils import old_div from random import randint import math @@ -69,7 +74,7 @@ def odd_even_merge(a, comp): odd_even_merge(even, comp) odd_even_merge(odd, comp) a[0] = even[0] - for i in range(1, len(a) / 2): + for i in range(1, old_div(len(a), 2)): a[2*i-1], a[2*i] = cond_swap(odd[i-1], even[i], comp) a[-1] = odd[-1] @@ -77,8 +82,8 @@ def odd_even_merge_sort(a, comp=bitwise_comparator): if len(a) == 1: return elif len(a) % 2 == 0: - lower = a[:len(a)/2] - upper = a[len(a)/2:] + lower = a[:old_div(len(a),2)] + upper = a[old_div(len(a),2):] odd_even_merge_sort(lower, comp) odd_even_merge_sort(upper, comp) a[:] = lower + upper @@ -134,7 +139,7 @@ def random_perm(n): WARNING: randomness fixed at compile-time, this is NOT secure """ - a = range(n) + a = list(range(n)) for i in range(n-1, 0, -1): j = randint(0, i) t = a[i] @@ -152,10 +157,10 @@ def configure_waksman(perm): n = len(perm) if n == 2: return [(perm[0], perm[0])] - I = [None] * (n/2) - O = [None] * (n/2) - p0 = [None] * (n/2) - p1 = [None] * (n/2) + I = [None] * (old_div(n,2)) + O = [None] * (old_div(n,2)) + p0 = [None] * (old_div(n,2)) + p1 = [None] * (old_div(n,2)) inv_perm = [0] * n for i, p in enumerate(perm): @@ -167,7 +172,7 @@ def configure_waksman(perm): except ValueError: break #print 'j =', j - O[j/2] = 0 + O[old_div(j,2)] = 0 via = 0 j0 = j while True: @@ -175,10 +180,10 @@ def configure_waksman(perm): i = inv_perm[j] #print ' p0[%d] = %d' % (inv_perm[j]/2, j/2) - p0[i/2] = j/2 + p0[old_div(i,2)] = old_div(j,2) - I[i/2] = i % 2 - O[j/2] = j % 2 + I[old_div(i,2)] = i % 2 + O[old_div(j,2)] = j % 2 #print ' O[%d] = %d' % (j/2, j % 2) if i % 2 == 1: i -= 1 @@ -195,7 +200,7 @@ def configure_waksman(perm): j += 1 #j, via = set_swapper(O, i, via, perm) #print ' p1[%d] = %d' % (i/2, perm[i]/2) - p1[i/2] = perm[i]/2 + p1[old_div(i,2)] = old_div(perm[i],2) #print ' i = %d, j = %d' %(i,j) if j == j0: @@ -203,8 +208,8 @@ def configure_waksman(perm): if None not in p0 and None not in p1: break - assert sorted(p0) == range(n/2) - assert sorted(p1) == range(n/2) + assert sorted(p0) == list(range(old_div(n,2))) + assert sorted(p1) == list(range(old_div(n,2))) p0_config = configure_waksman(p0) p1_config = configure_waksman(p1) return [I + O] + [a+b for a,b in zip(p0_config, p1_config)] @@ -216,22 +221,22 @@ def waksman(a, config, depth=0, start=0, reverse=False): a[0], a[1] = cond_swap_bit(a[0], a[1], config[depth][start]) return - a0 = [0] * (n/2) - a1 = [0] * (n/2) - for i in range(n/2): + a0 = [0] * (old_div(n,2)) + a1 = [0] * (old_div(n,2)) + for i in range(old_div(n,2)): if reverse: - a0[i], a1[i] = cond_swap_bit(a[2*i], a[2*i+1], config[depth][i + n/2 + start]) + a0[i], a1[i] = cond_swap_bit(a[2*i], a[2*i+1], config[depth][i + old_div(n,2) + start]) else: a0[i], a1[i] = cond_swap_bit(a[2*i], a[2*i+1], config[depth][i + start]) waksman(a0, config, depth+1, start, reverse) - waksman(a1, config, depth+1, start + n/2, reverse) + waksman(a1, config, depth+1, start + old_div(n,2), reverse) - for i in range(n/2): + for i in range(old_div(n,2)): if reverse: a[2*i], a[2*i+1] = cond_swap_bit(a0[i], a1[i], config[depth][i + start]) else: - a[2*i], a[2*i+1] = cond_swap_bit(a0[i], a1[i], config[depth][i + n/2 + start]) + a[2*i], a[2*i+1] = cond_swap_bit(a0[i], a1[i], config[depth][i + old_div(n,2) + start]) WAKSMAN_FUNCTIONS = {} @@ -263,10 +268,10 @@ def do_round(size, config_address, a_address, a2_address, inwards): sizeval = size #for k in range(n/2): - @for_range_parallel(200, n/2) + @for_range_parallel(200, old_div(n,2)) def f(k): j = cint(k) % sizeval - i = (cint(k) - j)/sizeval + i = old_div((cint(k) - j),sizeval) base = 2*i*sizeval in1, in2 = (base+j+j*inwards), (base+j+j*inwards+1*inwards+sizeval*outwards) @@ -295,7 +300,7 @@ def f(k): # going into middle of network @for_range(logn) def f(i): - size.write(n/(2*nblocks)) + size.write(old_div(n,(2*nblocks))) conf_address = MemValue(config.address + depth.read()*n) do_round(size, conf_address, a.address, a2.address, cint(1)) @@ -305,20 +310,20 @@ def f(i): nblocks.write(nblocks*2) depth.write(depth+1) - nblocks.write(nblocks/4) + nblocks.write(old_div(nblocks,4)) depth.write(depth-2) # and back out @for_range(logn-1) def f(i): - size.write(n/(2*nblocks)) + size.write(old_div(n,(2*nblocks))) conf_address = MemValue(config.address + depth.read()*n) do_round(size, conf_address, a.address, a2.address, cint(0)) for i in range(n): a[i] = a2[i] - nblocks.write(nblocks/2) + nblocks.write(old_div(nblocks,2)) depth.write(depth-1) ## going into middle of network @@ -373,7 +378,7 @@ def config_shuffle(n, value_type): if n & (n-1) != 0: # pad permutation to power of 2 m = 2**int(math.ceil(math.log(n, 2))) - perm += range(n, m) + perm += list(range(n, m)) config_bits = configure_waksman(perm) # 2-D array config = Array(len(config_bits) * len(perm), value_type.reg_type) diff --git a/Compiler/program.py b/Compiler/program.py index c7a71547..ca89f64a 100644 --- a/Compiler/program.py +++ b/Compiler/program.py @@ -1,12 +1,21 @@ +from __future__ import print_function +from __future__ import division # (C) 2017 University of Bristol. See License.txt +from future import standard_library +standard_library.install_aliases() +from builtins import next +from builtins import str +from builtins import range +from builtins import object +from past.utils import old_div from Compiler.config import * from Compiler.exceptions import * from Compiler.instructions_base import RegType import Compiler.instructions import Compiler.instructions_base -import compilerLib -import allocator as al +import Compiler.compilerLib +import Compiler.allocator as al import random import time import sys, os, errno @@ -14,6 +23,14 @@ from collections import defaultdict import itertools import math +from functools import reduce +import sys + + +IS_PY3 = sys.version[0] == "3" +if IS_PY3: + # If we're in python3, integers have unlimited size + long = int data_types = dict( @@ -43,8 +60,8 @@ def __init__(self, args, options, param=-1): self.param = param sshare = open('Data/SharingData.txt') self.P = int(sshare.readline()) - print 'p = %d' % self.P - prime_size = int(math.ceil(self.P.bit_length()/8))*8 + print('p = %d' % self.P) + prime_size = int(math.ceil(old_div(self.P.bit_length(),8)))*8 self.bit_length=64 self.security = 40 if prime_size<48: @@ -53,11 +70,11 @@ def __init__(self, args, options, param=-1): elif prime_size<85: self.bit_length=32 self.security=30 - print 'Prime size:', prime_size - print 'Default bit length:', self.bit_length - print 'Default statistical security parameter:', self.security + print('Prime size:', prime_size) + print('Default bit length:', self.bit_length) + print('Default statistical security parameter:', self.security) self.fdflag = options.fdflag - print 'Under Over Flow flag: ', self.fdflag + print('Under Over Flow flag: ', self.fdflag) self.schedule = [('start', [])] self.main_ctr = 0 self.tapes = [] @@ -100,12 +117,12 @@ def max_par_tapes(self): running[tape] -= 1 else: raise CompilerError('Invalid schedule action') - res = max(res, sum(running.itervalues())) + res = max(res, sum(running.values())) return res def init_names(self, args): self.programs_dir=args[0]; - print 'Compiling program in', self.programs_dir + print('Compiling program in', self.programs_dir) if self.programs_dir.endswith('/'): self.programs_dir = self.programs_dir[:-1] progname = self.programs_dir.split('/')[-1] @@ -114,7 +131,7 @@ def init_names(self, args): progname = progname[:-4] self.infile = self.programs_dir + '/' + progname + '.mpc' - print progname + print(progname) """ self.name is input file name (minus extension) + any optional arguments. Used to generate output filenames @@ -191,7 +208,7 @@ def update_req(self, tape): def read_memory(self, filename): """ Read the clear and shared memory from a file """ f = open(filename) - n = int(f.next()) + n = int(next(f)) self.mem_c = [0]*n self.mem_s = [0]*n mem = self.mem_c @@ -219,8 +236,8 @@ def reset_values(self): """ Reset register and memory values. """ for tape in self.tapes: tape.reset_registers() - self.mem_c = range(USER_MEM + TMP_MEM) - self.mem_s = range(USER_MEM + TMP_MEM) + self.mem_c = list(range(USER_MEM + TMP_MEM)) + self.mem_s = list(range(USER_MEM + TMP_MEM)) random.seed(0) def write_bytes(self, outfile=None): @@ -232,7 +249,7 @@ def write_bytes(self, outfile=None): sch_filename = self.programs_dir + '/%s.sch' % self.name sch_file = open(sch_filename, 'w') - print 'Writing to', sch_filename + print('Writing to', sch_filename) sch_file.write(str(self.max_par_tapes()) + '\n') sch_file.write(str(len(nonempty_tapes)) + '\n') sch_file.write(' '.join(tape.name for tape in nonempty_tapes) + '\n') @@ -243,7 +260,7 @@ def write_bytes(self, outfile=None): for sch in self.schedule: # schedule may still contain empty tapes: ignore these - tapes = filter(lambda x: not x[0].is_empty(), sch[1]) + tapes = [x for x in sch[1] if not x[0].is_empty()] # no empty line if not tapes: continue @@ -333,7 +350,7 @@ def malloc(self, size, mem_type, reg_type=None): addr = self.allocated_mem[mem_type] self.allocated_mem[mem_type] += size if len(str(addr)) != len(str(addr + size)): - print "Memory of type '%s' now of size %d" % (mem_type, addr + size) + print("Memory of type '%s' now of size %d" % (mem_type, addr + size)) self.allocated_mem_blocks[addr,mem_type] = size return addr @@ -351,9 +368,9 @@ def finalize_memory(self): # reset register counter to 0 self.curr_tape.init_registers() library.jmp(0); # Create a new basic block for the set memory instructions - for mem_type,size in self.allocated_mem.items(): + for mem_type,size in list(self.allocated_mem.items()): if size: - print "Memory of type '%s' of size %d" % (mem_type, size) + print("Memory of type '%s' of size %d" % (mem_type, size)) if mem_type in self.types: self.types[mem_type].load_mem(size - 1, mem_type) else: @@ -364,13 +381,13 @@ def public_input(self, x): def set_bit_length(self, bit_length): self.bit_length = bit_length - print 'Changed bit length for comparisons etc. to', bit_length + print('Changed bit length for comparisons etc. to', bit_length) def set_security(self, security): self.security = security - print 'Changed statistical security for comparison etc. to', security + print('Changed statistical security for comparison etc. to', security) -class Tape: +class Tape(object): """ A tape contains a list of basic blocks, onto which instructions are added. """ def __init__(self, name, program, param=-1): """ Set prime p and the initial instructions and registers. """ @@ -464,7 +481,7 @@ def start_new_basicblock(self, scope=False, name=''): self.basicblocks.append(sub) self.active_basicblock = sub self.req_node.add_block(sub) - print 'Compiling basic block', sub.name + print('Compiling basic block', sub.name) def init_registers(self): self.reset_registers() @@ -490,8 +507,8 @@ def purge(self): def unpurged(function): def wrapper(self, *args, **kwargs): if self.purged: - print '%s called on purged block %s, ignoring' % \ - (function.__name__, self.name) + print('%s called on purged block %s, ignoring' % \ + (function.__name__, self.name)) return return function(self, *args, **kwargs) return wrapper @@ -499,13 +516,13 @@ def wrapper(self, *args, **kwargs): @unpurged def optimize(self, options): if len(self.basicblocks) == 0: - print 'Tape %s is empty' % self.name + print('Tape %s is empty' % self.name) return if self.if_states: raise CompilerError('Unclosed if/else blocks') - print 'Processing tape', self.name, 'with %d blocks' % len(self.basicblocks) + print('Processing tape', self.name, 'with %d blocks' % len(self.basicblocks)) for block in self.basicblocks: al.determine_scope(block, options) @@ -515,14 +532,14 @@ def optimize(self, options): if (options.merge_opens and self.merge_opens) or options.dead_code_elimination: for i,block in enumerate(self.basicblocks): if len(block.instructions) > 0: - print 'Processing basic block %s, %d/%d, %d instructions' % \ + print('Processing basic block %s, %d/%d, %d instructions' % \ (block.name, i, len(self.basicblocks), \ - len(block.instructions)) + len(block.instructions))) # the next call is necessary for allocation later even without merging merger = al.Merger(block, options) if options.dead_code_elimination: if len(block.instructions) > 10000: - print 'Eliminate dead code...' + print('Eliminate dead code...') merger.eliminate_dead_code() if options.merge_opens and self.merge_opens: if len(block.instructions) == 0: @@ -530,17 +547,17 @@ def optimize(self, options): block.defined_registers = set() continue if len(block.instructions) > 10000: - print 'Merging open instructions...' + print('Merging open instructions...') numrounds = merger.longest_paths_merge() if numrounds > 0: - print 'Program requires %d rounds of communication' % numrounds + print('Program requires %d rounds of communication' % numrounds) numinv = sum(len(i.args) for i in block.instructions if isinstance(i, Compiler.instructions.startopen_class)) if numinv > 0: - print 'Program requires %d invocations' % numinv + print('Program requires %d invocations' % numinv) if options.dead_code_elimination: - block.instructions = filter(lambda x: x is not None, block.instructions) + block.instructions = [x for x in block.instructions if x is not None] if not (options.merge_opens and self.merge_opens): - print 'Not merging open instructions in tape %s' % self.name + print('Not merging open instructions in tape %s' % self.name) # add jumps offset = 0 @@ -554,14 +571,14 @@ def optimize(self, options): block.adjust_jump() # now remove any empty blocks (must be done after setting jumps) - self.basicblocks = filter(lambda x: len(x.instructions) != 0, self.basicblocks) + self.basicblocks = [x for x in self.basicblocks if len(x.instructions) != 0] # allocate registers reg_counts = self.count_regs() if not options.noreallocate: - print 'Tape register usage:', reg_counts - print 'modp: %d clear, %d secret' % (reg_counts[RegType.ClearModp], reg_counts[RegType.SecretModp]) - print 'Re-allocating...' + print('Tape register usage:', reg_counts) + print('modp: %d clear, %d secret' % (reg_counts[RegType.ClearModp], reg_counts[RegType.SecretModp])) + print('Re-allocating...') allocator = al.StraightlineAllocator(REG_MAX) def alloc_loop(block): for reg in block.used_from_scope: @@ -571,8 +588,8 @@ def alloc_loop(block): alloc_loop(child) for i,block in enumerate(reversed(self.basicblocks)): if len(block.instructions) > 10000: - print 'Allocating %s, %d/%d' % \ - (block.name, i, len(self.basicblocks)) + print('Allocating %s, %d/%d' % \ + (block.name, i, len(self.basicblocks))) if block.exit_condition is not None: jump = block.exit_condition.get_relative_jump() if jump != -1 and \ @@ -583,10 +600,10 @@ def alloc_loop(block): allocator.process(block.instructions, block.alloc_pool) # offline data requirements - print 'Compile offline data requirements...' + print('Compile offline data requirements...') self.req_num = self.req_tree.aggregate() - print 'Tape requires', self.req_num - for req,num in self.req_num.items(): + print('Tape requires', self.req_num) + for req,num in list(self.req_num.items()): if num == float('inf'): num = -1 @@ -597,7 +614,7 @@ def alloc_loop(block): self.basicblocks[-1].instructions.append( Compiler.instructions.reqbl(self.req_bit_length['p'], add_to_prog=False)) - print 'Tape requires prime bit length', self.req_bit_length['p'] + print('Tape requires prime bit length', self.req_bit_length['p']) @unpurged def _get_instructions(self): @@ -612,12 +629,15 @@ def get_encoding(self): @unpurged def get_bytes(self): """ Get the byte encoding of the program as an actual string of bytes. """ - return "".join(str(i.get_bytes()) for i in self._get_instructions() if i is not None) + if IS_PY3: + return "".join(str(i.get_bytes(), encoding="latin1") for i in self._get_instructions() if i is not None) + else: + return "".join(bytes(i.get_bytes()) for i in self._get_instructions() if i is not None) @unpurged def write_encoding(self, filename): """ Write the readable encoding to a file. """ - print 'Writing to', filename + print('Writing to', filename) f = open(filename, 'w') for line in self.get_encoding(): f.write(str(line) + '\n') @@ -626,7 +646,7 @@ def write_encoding(self, filename): @unpurged def write_str(self, filename): """ Write the sequence of instructions to a file. """ - print 'Writing to', filename + print('Writing to', filename) f = open(filename, 'w') n = 0 for block in self.basicblocks: @@ -642,10 +662,10 @@ def write_bytes(self, filename=None): """ Write the program's byte encoding to a file. """ if filename is None: filename = self.outfile - print 'Writing to', filename + print('Writing to', filename) if not filename.endswith('.bc'): filename += '.bc' - print 'Writing to', filename + print('Writing to', filename) f = open(filename, 'w') f.write(self.get_bytes()) f.close() @@ -674,9 +694,9 @@ def __init__(self, init={}): super(Tape.ReqNum, self).__init__(lambda: 0, init) def __add__(self, other): res = Tape.ReqNum() - for i,count in self.items(): + for i,count in list(self.items()): res[i] += count - for i,count in other.items(): + for i,count in list(other.items()): res[i] += count return res def __mul__(self, other): @@ -702,7 +722,7 @@ def __str__(self): % (num, req[0], req[2]) \ if req[1] == 'input' \ else '%s %ss in %s' % (num, req[1], req[0]) \ - for req,num in self.items()) + for req,num in list(self.items())) def __repr__(self): return repr(dict(self)) @@ -768,7 +788,7 @@ class Register(object): The 'value' property is for emulation. """ - __slots__ = ["reg_type", "program", "i", "value", "_is_active", \ + __slots__ = ["reg_type", "program", "i", "_is_active", \ "size", "vector", "vectorbase", "caller", \ "can_eliminate"] @@ -796,18 +816,18 @@ def __init__(self, reg_type, program, value=None, size=None, i=None): else: self.caller = None if self.i % 1000000 == 0 and self.i > 0: - print "Initialized %d registers at" % self.i, time.asctime() + print("Initialized %d registers at" % self.i, time.asctime()) def set_size(self, size): if self.size == size: return elif self.size == 1 and self.vectorbase is self: - if '%s%d' % (self.reg_type, self.i) in compilerLib.VARS: + if '%s%d' % (self.reg_type, self.i) in Compiler.compilerLib.VARS: # create vector register in assembly mode self.size = size self.vector = [self] for i in range(1,size): - reg = compilerLib.VARS['%s%d' % (self.reg_type, self.i + i)] + reg = Compiler.compilerLib.VARS['%s%d' % (self.reg_type, self.i + i)] reg.set_vectorbase(self) self.vector.append(reg) else: diff --git a/Compiler/tools.py b/Compiler/tools.py index 4a7cd892..7ec3d772 100644 --- a/Compiler/tools.py +++ b/Compiler/tools.py @@ -1,3 +1,4 @@ +from builtins import object import itertools class chain(object): diff --git a/Compiler/types.py b/Compiler/types.py index ede0c09c..5ccbb5e1 100644 --- a/Compiler/types.py +++ b/Compiler/types.py @@ -14,16 +14,30 @@ sregint sbit """ +from __future__ import print_function +from __future__ import division ##@types.py +from builtins import zip +from builtins import str +from builtins import range +from past.utils import old_div +from builtins import object from Compiler.program import Tape from Compiler.exceptions import * from Compiler.instructions import * from Compiler.instructions_base import * -from floatingpoint import two_power -import comparison, floatingpoint +from Compiler.floatingpoint import two_power +import Compiler.comparison +import Compiler.floatingpoint import math -import util import operator +import sys +from functools import reduce + + +if sys.version[0] == "3": + # If we're in python3, integers have unlimited size + long = int class MPCThread(object): @@ -129,16 +143,16 @@ def square(self): return self * self def __add__(self, other): - if other is 0 or other is 0L: + if other is 0: return self else: var = self.add(other) return var def __mul__(self, other): - if other is 0 or other is 0L: + if other is 0: return 0 - elif other is 1 or other is 1L: + elif other is 1: return self else: return self.mul(other) @@ -257,7 +271,7 @@ def print_reg(self, comment=''): print_reg(self) print_char4(" # ") print_char4(comment) - print_char("\n") + print_char("\n") @set_instruction_type @vectorize @@ -319,9 +333,13 @@ def __rsub__(self, other): def __div__(self, other): return self.clear_op(other, divc, divci) + __truediv__ = __div__ def __rdiv__(self, other): return self.coerce_op(other, divc, True) + __rtruediv__ = __rdiv__ + + __hash__ = object.__hash__ def __eq__(self, other): if isinstance(other, (_clear, int, long)): @@ -399,12 +417,12 @@ def load_int(self, val): ldi(self, val) else: max = 2 ** 31 - 1 - sign = abs(val) / val + sign = old_div(abs(val), val) val = abs(val) chunks = [] while val: mod = val % max - val = (val - mod) / max + val = old_div((val - mod), max) chunks.append(mod) sum = cint(sign * chunks.pop()) for i, chunk in enumerate(reversed(chunks)): @@ -510,7 +528,7 @@ def bit_decompose(self, bit_length=None): if bit_length == 0: return [] bit_length = bit_length or program.bit_length - return floatingpoint.bits(self, bit_length) + return Compiler.floatingpoint.bits(self, bit_length) def legendre(self): r"""Returns the legendre symbol of x, wrt the cint prime p @@ -641,12 +659,14 @@ def __neg__(self): def __div__(self, other): return self.int_op(other, divint) + __truediv__ = __div__ def __rdiv__(self, other): return self.int_op(other, divint, True) + __rtruediv__ = __rdiv__ def __mod__(self, other): - return self - (self / other) * other + return self - (old_div(self, other)) * other def __rmod__(self, other): return regint(other) % self @@ -654,6 +674,8 @@ def __rmod__(self, other): def __rpow__(self, other): return other ** cint(self) + __hash__ = object.__hash__ + def __eq__(self, other): return self.int_op(other, eqint) @@ -683,7 +705,7 @@ def __lshift__(self, other): def __rshift__(self, other): if isinstance(other, (int, long)): - return self / 2 ** other + return old_div(self, 2 ** other) else: return regint(cint(self) >> other) @@ -717,7 +739,7 @@ def bit_decompose(self, bit_length=None): x = self two = regint(2) for i in range(bit_length or program.bit_length): - y = x / two + y = old_div(x, two) res.append(x - two * y) x = y return res @@ -842,10 +864,12 @@ def __rsub__(self, other): @vectorize def __div__(self, other): return NotImplemented + __truediv__ = __div__ @vectorize def __rdiv__(self, other): return NotImplemented + __rtruediv__ = __rdiv__ @set_instruction_type @vectorize @@ -982,6 +1006,7 @@ def __div__(self, other): """ #return self.secret_op(other, divsint) return self.div(other) + __truediv__ = __div__ def __rdiv__(self, other): r""" @@ -989,6 +1014,7 @@ def __rdiv__(self, other): """ # return self.secret_op(other, divsint, True) return self.div(other, True) + __rtruediv__ = __rdiv__ def __lshift__(self, other): return self.secret_op(other, shlsint) @@ -1075,12 +1101,14 @@ def __rsub__(self, other): @vectorize def __div__(self, other): - return self * (self.clear_type(1) / other) + return self * (old_div(self.clear_type(1), other)) + __truediv__ = __div__ @vectorize def __rdiv__(self, other): a, b = self.get_random_square() - return other * a / (a * self).reveal() + return old_div(other * a, (a * self).reveal()) + __rtruediv__ = __rdiv__ @set_instruction_type @vectorize @@ -1234,6 +1262,8 @@ def __gt__(self, other): ltzsint(res, other_local) return res + __hash__ = object.__hash__ + def __eq__(self, other): res = sbit() other_local = parse_sregint(other) @@ -1329,7 +1359,7 @@ def get_random_int(cls, bits): assigns a to be a random integer in the range [0..,2^n] """ res = sint() - comparison.PRandInt(res, bits) + Compiler.comparison.PRandInt(res, bits) return res @classmethod @@ -1370,7 +1400,7 @@ def __lt__(self, other, bit_length=None, security=None): return other > self res = sint() - comparison.LTZ(res, self - other, bit_length or program.bit_length + 1, + Compiler.comparison.LTZ(res, self - other, bit_length or program.bit_length + 1, security or program.security) return res @@ -1381,7 +1411,7 @@ def __gt__(self, other, bit_length=None, security=None): return other < self res = sint() - comparison.LTZ(res, other - self, bit_length or program.bit_length + 1, + Compiler.comparison.LTZ(res, other - self, bit_length or program.bit_length + 1, security or program.security) return res @@ -1396,12 +1426,14 @@ def __ge__(self, other, bit_length=None, security=None): return 1 - self.less_than(other, bit_length, security) + __hash__ = object.__hash__ + @read_mem_value @vectorize def __eq__(self, other, bit_length=None, security=None): if isinstance(other, (cfloat, sfloat)): return other == self - return floatingpoint.EQZ(self - other, bit_length or program.bit_length, + return Compiler.floatingpoint.EQZ(self - other, bit_length or program.bit_length, security or program.security) def __ne__(self, other, bit_length=None, security=None): @@ -1435,11 +1467,11 @@ def mod2m(self, m, bit_length=None, security=None, signed=True): return self res = sint() if m == 1: - comparison.Mod2(res, self, bit_length, security, signed) + Compiler.comparison.Mod2(res, self, bit_length, security, signed) else: - comparison.Mod2m(res, self, bit_length, m, security, signed) + Compiler.comparison.Mod2m(res, self, bit_length, m, security, signed) else: - res, pow2 = floatingpoint.Trunc(self, bit_length, m, security, True) + res, pow2 = Compiler.floatingpoint.Trunc(self, bit_length, m, security, True) return res @vectorize @@ -1454,7 +1486,7 @@ def __rpow__(self, base): def pow2(self, bit_length=None, security=None): - return floatingpoint.Pow2(self, bit_length or program.bit_length, \ + return Compiler.floatingpoint.Pow2(self, bit_length or program.bit_length, \ security or program.security) def __lshift__(self, other): @@ -1469,12 +1501,12 @@ def __rshift__(self, other, bit_length=None, security=None): if other == 0: return self res = sint() - comparison.Trunc(res, self, bit_length, other, security, True) + Compiler.comparison.Trunc(res, self, bit_length, other, security, True) return res elif isinstance(other, sint): - return floatingpoint.Trunc(self, bit_length, other, security) + return Compiler.floatingpoint.Trunc(self, bit_length, other, security) else: - return floatingpoint.Trunc(self, bit_length, sint(other), security) + return Compiler.floatingpoint.Trunc(self, bit_length, sint(other), security) right_shift = __rshift__ @@ -1483,14 +1515,14 @@ def __rlshift__(self, other): @vectorize def __rrshift__(self, other): - return floatingpoint.Trunc(other, program.bit_length, self, program.security) + return Compiler.floatingpoint.Trunc(other, program.bit_length, self, program.security) def bit_decompose(self, bit_length=None, security=None): if bit_length == 0: return [] bit_length = bit_length or program.bit_length security = security or program.security - return floatingpoint.BitDec(self, bit_length, bit_length, security) + return Compiler.floatingpoint.BitDec(self, bit_length, bit_length, security) sint.bit_type = sint @@ -1688,6 +1720,8 @@ def __neg__(self): def __rsub__(self, other): return -self + other + __hash__ = object.__hash__ + @vectorize def __eq__(self, other): """ parses all types to fix registers and performs test. @@ -1789,11 +1823,12 @@ def __ne__(self, other): def __div__(self, other): other = parse_type(other) if isinstance(other, cfix): - return cfix(library.cint_cint_division(self.v, other.v, self.k, self.f)) + return cfix(Compiler.library.cint_cint_division(self.v, other.v, self.k, self.f)) elif isinstance(other, sfix): - return sfix(library.FPDiv(self.v, other.v, self.k, self.f, other.kappa)) + return sfix(Compiler.library.FPDiv(self.v, other.v, self.k, self.f, other.kappa)) else: raise TypeError('Incompatible fixed point types in division') + __truediv__ = __div__ @vectorize def print_fix(self): @@ -1923,7 +1958,7 @@ def mul(self, other): else: other = parse_type(other) if isinstance(other, (sfix, cfix)): - val = floatingpoint.TruncPr(self.v * other.v, self.k * 2, self.f, self.kappa) + val = Compiler.floatingpoint.TruncPr(self.v * other.v, self.k * 2, self.f, self.kappa) return sfix(val) elif isinstance(other, cfix.scalars): scalar_fix = cfix(other) @@ -1946,6 +1981,8 @@ def __neg__(self): def __rsub__(self, other): return -(self) + other + __hash__ = object.__hash__ + @vectorize def __eq__(self, other): if isinstance(other, sfloat): @@ -2016,15 +2053,16 @@ def __ne__(self, other): def __div__(self, other): other = parse_type(other) if isinstance(other, sfix): - return sfix(library.FPDiv(self.v, other.v, self.k, self.f, self.kappa)) + return sfix(Compiler.library.FPDiv(self.v, other.v, self.k, self.f, self.kappa)) elif isinstance(other, cfix): - return sfix(library.sint_cint_division(self.v, other.v, self.k, self.f, self.kappa)) + return sfix(Compiler.library.sint_cint_division(self.v, other.v, self.k, self.f, self.kappa)) else: raise TypeError('Incompatible fixed point types in division') + __truediv__ = __div__ @vectorize def compute_reciprocal(self): - return sfix(library.FPDiv(cint(2) ** self.f, self.v, self.k, self.f, self.kappa, True)) + return sfix(Compiler.library.FPDiv(cint(2) ** self.f, self.v, self.k, self.f, self.kappa, True)) def reveal(self): val = self.v.reveal() @@ -2080,7 +2118,7 @@ def add_err(self, flag): @staticmethod def convert_float(v, vlen, plen): - v, p, z, s = floatingpoint.convert_float(v, vlen, plen) + v, p, z, s = Compiler.floatingpoint.convert_float(v, vlen, plen) err = sint(0) return v, p, z, s, err @@ -2104,14 +2142,14 @@ def __init__(self, v, p=None, z=None, s=None, err=None, size=None): s = v.s v = v.v elif isinstance(v, sint): - v, p, z, s = floatingpoint.Int2FL(v, program.bit_length, + v, p, z, s = Compiler.floatingpoint.Int2FL(v, program.bit_length, self.vlen, self.kappa) err = self.__flow_detect__(p) elif isinstance(v, sfix): f = v.f - v, p, z, s = floatingpoint.Int2FL(v.v, v.k, + v, p, z, s = Compiler.floatingpoint.Int2FL(v.v, v.k, self.vlen, self.kappa) p = p - f err = self.__flow_detect__(p) @@ -2122,14 +2160,14 @@ def __init__(self, v, p=None, z=None, s=None, err=None, size=None): if isinstance(v, (int,long)): if not ((v >= 2 ** (self.vlen - 1) and v < 2 ** (self.vlen)) or v == 0): raise CompilerError('Floating point number malformed: significand') - self.v = library.load_int_to_secret(v) + self.v = Compiler.library.load_int_to_secret(v) else: self.v = v if isinstance(p, int): if not (p >= -2 ** (self.plen - 1) and p < 2 ** (self.plen - 1)): raise CompilerError( 'Floating point number malformed: exponent %d not unsigned %d-bit integer' % (p, self.plen)) - self.p = library.load_int_to_secret(p) + self.p = Compiler.library.load_int_to_secret(p) else: self.p = p if isinstance(z, int): @@ -2149,7 +2187,7 @@ def __init__(self, v, p=None, z=None, s=None, err=None, size=None): if isinstance(err, int): if not (err >= 0): raise CompilerError('Floating point number malformed: err') - self.err = library.load_int_to_secret(err) + self.err = Compiler.library.load_int_to_secret(err) else: self.err = err program.curr_tape.require_bit_length(2*self.vlen+self.kappa+1) @@ -2196,7 +2234,7 @@ def add(self, other): z1 = self.z z2 = other.z a = p1.less_than(p2, self.plen, self.kappa) - b = floatingpoint.EQZ(p1 - p2, self.plen, self.kappa) + b = Compiler.floatingpoint.EQZ(p1 - p2, self.plen, self.kappa) c = v1.less_than(v2, self.vlen, self.kappa) ap1 = a * p1 ap2 = a * p2 @@ -2212,9 +2250,9 @@ def add(self, other): vmax = bneg * (av2 + v1 - av1) + b * (cv2 + v1 - cv1) vmin = bneg * (av1 + v2 - av2) + b * (cv1 + v2 - cv2) s3 = s1 + s2 - 2 * s1 * s2 - comparison.LTZ(d, self.vlen + pmin - pmax + sfloat.round_nearest, + Compiler.comparison.LTZ(d, self.vlen + pmin - pmax + sfloat.round_nearest, self.plen, self.kappa) - pow_delta = floatingpoint.Pow2((1 - d) * (pmax - pmin), + pow_delta = Compiler.floatingpoint.Pow2((1 - d) * (pmax - pmin), self.vlen + 1 + sfloat.round_nearest, self.kappa) # deviate from paper for more precision @@ -2222,27 +2260,27 @@ def add(self, other): v3 = vmax v4 = vmax * pow_delta + (1 - 2 * s3) * vmin v = (d * v3 + (1 - d) * v4) * two_power(self.vlen + sfloat.round_nearest) \ - * floatingpoint.Inv(pow_delta) - comparison.Trunc(t, v, 2 * self.vlen + 1 + sfloat.round_nearest, + * Compiler.floatingpoint.Inv(pow_delta) + Compiler.comparison.Trunc(t, v, 2 * self.vlen + 1 + sfloat.round_nearest, self.vlen - 1, self.kappa, False) v = t - u = floatingpoint.BitDec(v, self.vlen + 2 + sfloat.round_nearest, + u = Compiler.floatingpoint.BitDec(v, self.vlen + 2 + sfloat.round_nearest, self.vlen + 2 + sfloat.round_nearest, self.kappa, - range(1 + sfloat.round_nearest, - self.vlen + 2 + sfloat.round_nearest)) + list(range(1 + sfloat.round_nearest, + self.vlen + 2 + sfloat.round_nearest))) # using u[0] doesn't seem necessary - h = floatingpoint.PreOR(u[:sfloat.round_nearest:-1], self.kappa) + h = Compiler.floatingpoint.PreOR(u[:sfloat.round_nearest:-1], self.kappa) p0 = self.vlen + 1 - sum(h) pow_p0 = 1 + sum([two_power(i) * (1 - h[i]) for i in range(len(h))]) if self.round_nearest: t2, overflow = \ - floatingpoint.TruncRoundNearestAdjustOverflow(pow_p0 * v, + Compiler.floatingpoint.TruncRoundNearestAdjustOverflow(pow_p0 * v, self.vlen + 3, self.vlen, self.kappa) p0 = p0 - overflow else: - comparison.Trunc(t2, pow_p0 * v, self.vlen + 2, 2, self.kappa, False) + Compiler.comparison.Trunc(t2, pow_p0 * v, self.vlen + 2, 2, self.kappa, False) v = t2 # deviate for more precision # p = pmax - p0 + 1 - d @@ -2250,7 +2288,7 @@ def add(self, other): zz = self.z * other.z zprod = 1 - self.z - other.z + zz v = zprod * t2 + self.z * v2 + other.z * v1 - z = floatingpoint.EQZ(v, self.vlen, self.kappa) + z = Compiler.floatingpoint.EQZ(v, self.vlen, self.kappa) p = (zprod * p + self.z * p2 + other.z * p1) * (1 - z) s = (1 - b) * (a * other.s + aneg * self.s) + b * (c * other.s + cneg * self.s) s = zprod * s + (other.z - zz) * self.s + (self.z - zz) * other.s @@ -2278,15 +2316,15 @@ def mul(self, other): v2 = sint() b = sint() c2expl = cint() - comparison.ld2i(c2expl, self.vlen) + Compiler.comparison.ld2i(c2expl, self.vlen) if sfloat.round_nearest: - v1 = comparison.TruncRoundNearest(self.v * other.v, 2 * self.vlen, + v1 = Compiler.comparison.TruncRoundNearest(self.v * other.v, 2 * self.vlen, self.vlen - 1, self.kappa) else: - comparison.Trunc(v1, self.v * other.v, 2 * self.vlen, self.vlen - 1, self.kappa, False) + Compiler.comparison.Trunc(v1, self.v * other.v, 2 * self.vlen, self.vlen - 1, self.kappa, False) t = v1 - c2expl - comparison.LTZ(b, t, self.vlen + 1, self.kappa) - comparison.Trunc(v2, b * v1 + v1, self.vlen + 1, 1, self.kappa, False) + Compiler.comparison.LTZ(b, t, self.vlen + 1, self.kappa) + Compiler.comparison.Trunc(v2, b * v1 + v1, self.vlen + 1, 1, self.kappa, False) z = self.z + other.z - self.z * other.z # = OR(z1, z2) s = self.s + other.s - 2 * self.s * other.s # = XOR(s1,s2) p = (self.p + other.p - b + self.vlen) * (1 - z) @@ -2309,9 +2347,9 @@ def mul(self, other): def local_division_ABZS12(self, other): if isinstance(other, (cfloat, sfloat)): l = self.vlen - v = floatingpoint.SDiv_ABZS12(self.v, other.v + other.z, l, self.kappa) + v = Compiler.floatingpoint.SDiv_ABZS12(self.v, other.v + other.z, l, self.kappa) b = v.less_than(2 ** l, l + 1, self.kappa) - v = floatingpoint.Trunc(v * b + v, l + 1, 1, self.kappa) + v = Compiler.floatingpoint.Trunc(v * b + v, l + 1, 1, self.kappa) p = (1 - self.z) * (self.p - other.p - l + 1 - b) z = self.z @@ -2326,7 +2364,7 @@ def local_division_ABZS12(self, other): else: other_parse = parse_float(other) - return self / other_parse + return old_div(self, other_parse) ## # realizes the division protocol for several different types. @@ -2334,7 +2372,7 @@ def local_division_ABZS12(self, other): # @return sloat: new sfloat instance def local_division(self, other): if isinstance(other, (cfloat, sfloat)): - v = floatingpoint.SDiv(self.v, other.v + other.z * (2 ** self.vlen - 1), + v = Compiler.floatingpoint.SDiv(self.v, other.v + other.z * (2 ** self.vlen - 1), self.vlen, self.kappa) b = v.less_than(two_power(self.vlen - 1), self.vlen + 1, self.kappa) overflow = v.greater_equal(two_power(self.vlen), self.vlen + 1, self.kappa) @@ -2358,7 +2396,7 @@ def local_division(self, other): else: other_parse = parse_float(other) - return self / other_parse + return old_div(self, other_parse) def __sub__(self, other): @@ -2369,6 +2407,7 @@ def __rsub__(self, other): def __div__(self, other): return self.local_division_ABZS12(other) + __truediv__ = __div__ @vectorize def __neg__(self): @@ -2383,7 +2422,7 @@ def __neg__(self): @vectorize def __lt__(self, other): if isinstance(other, (cfloat, sfloat)): - return floatingpoint.FLLT(self, other) + return Compiler.floatingpoint.FLLT(self, other) else: other_parse = parse_float(other) return self < other_parse @@ -2394,8 +2433,8 @@ def __lt__(self, other): # @param other: value comparing self, could be any type # @return sint: new sint bitwise instance def __gt__(self, other): - # return floatingpoint.FLLT(other, self) - return (other - self) < 0 # floatingpoint.FLLTZ(other - self) + # return Compiler.floatingpoint.FLLT(other, self) + return (other - self) < 0 # Compiler.floatingpoint.FLLTZ(other - self) ## # realizes the less equal protocol for several different types. @@ -2411,6 +2450,8 @@ def __le__(self, other): def __ge__(self, other): return 1 - (self < other) + __hash__ = object.__hash__ + ## # realizes the equality test protocol for several different types. # @param other: value comparing self, could be any type @@ -2424,8 +2465,8 @@ def __eq__(self, other): t = t == 0 # the sign can be both ways for zeroes both_zero = self.z * other.z - return (floatingpoint.EQZ(self.v - other.v, self.vlen, self.kappa) * \ - floatingpoint.EQZ(self.p - other.p, self.plen, self.kappa) * \ + return (Compiler.floatingpoint.EQZ(self.v - other.v, self.vlen, self.kappa) * \ + Compiler.floatingpoint.EQZ(self.p - other.p, self.plen, self.kappa) * \ (1 - self.s - other.s + 2 * self.s * other.s) * \ (1 - both_zero) + both_zero) * t else: @@ -2523,15 +2564,15 @@ def __init__(self, v, p=None, z=None, s=None, size=None): # raise CompilerError('Unsupported operation for clear registries') v_clear = parse_type(v) f = v_clear.f - v, p, z, s = library.int2FL_plain(v_clear.v, program.bit_length, self.vlen, self.kappa) + v, p, z, s = Compiler.library.int2FL_plain(v_clear.v, program.bit_length, self.vlen, self.kappa) p = p - f - # v, p, z, s = library.int2FL_plain(v, program.bit_length, self.vlen, self.kappa) + # v, p, z, s = Compiler.library.int2FL_plain(v, program.bit_length, self.vlen, self.kappa) # instantiate v, p z, s as int elif isinstance(v, cfloat.scalars): # convert float verfies p < 2** vlen, which is then done again here. # this is for legacy reasons, the method is a geacy method embedded in sfloat - v, p, z, s = floatingpoint.convert_float(v, self.vlen, self.plen) + v, p, z, s = Compiler.floatingpoint.convert_float(v, self.vlen, self.plen) else: # missmatch of types validation raise CompilerError('Missmatching input type') @@ -2696,10 +2737,10 @@ def get_slice(self, index): def __getitem__(self, index): if isinstance(index, slice): start, stop, step = self.get_slice(index) - res_length = (stop - start - 1) / step + 1 + res_length = old_div((stop - start - 1), step) + 1 res = Array(res_length, self.value_type) - @library.for_range(res_length) + @Compiler.library.for_range(res_length) def f(i): res[i] = self[start + i * step] @@ -2711,7 +2752,7 @@ def __setitem__(self, index, value): start, stop, step = self.get_slice(index) source_index = MemValue(0) - @library.for_range(start, stop, step) + @Compiler.library.for_range(start, stop, step) def f(i): self[i] = value[source_index] source_index.iadd(1) @@ -2737,7 +2778,7 @@ def assign(self, other): def loop(i): self[i] = other[i] - library.range_loop(loop, len(self)) + Compiler.library.range_loop(loop, len(self)) elif isinstance(other, Tape.Register): if len(other) == self.length: self[0] = other @@ -2752,7 +2793,7 @@ def assign_all(self, value): mem_value = MemValue(value) n_loops = 8 if len(self) > 2 ** 20 else 1 - @library.for_range_multithread(n_loops, 1024, len(self)) + @Compiler.library.for_range_multithread(n_loops, 1024, len(self)) def f(i): self[i] = mem_value @@ -2782,7 +2823,7 @@ def __len__(self): return self.rows def assign_all(self, value): - @library.for_range(len(self)) + @Compiler.library.for_range(len(self)) def f(i): self[i].assign_all(value) @@ -2836,7 +2877,7 @@ def __setitem__(self, index, value): class sfloatArray(Array): def __init__(self, length, address=None): - print length, address + print(length, address) self.matrix = Matrix(length, 5, sint, address) self.length = length self.value_type = sfloat @@ -2910,7 +2951,8 @@ class _mem(_number): __add__ = lambda self, other: self.read() + other __sub__ = lambda self, other: self.read() - other __mul__ = lambda self, other: self.read() * other - __div__ = lambda self, other: self.read() / other + __div__ = lambda self, other: old_div(self.read(), other) + __truediv__ = __div__ __mod__ = lambda self, other: self.read() % other __pow__ = lambda self, other: self.read() ** other __neg__ = lambda self, other: -self.read() @@ -2929,7 +2971,7 @@ class _mem(_number): __radd__ = lambda self, other: other + self.read() __rsub__ = lambda self, other: other - self.read() __rmul__ = lambda self, other: other * self.read() - __rdiv__ = lambda self, other: other / self.read() + __rdiv__ = lambda self, other: old_div(other, self.read()) __rmod__ = lambda self, other: other % self.read() __rand__ = lambda self, other: other & self.read() __rxor__ = lambda self, other: other ^ self.read() @@ -2938,7 +2980,7 @@ class _mem(_number): __iadd__ = lambda self, other: self.write(self.read() + other) __isub__ = lambda self, other: self.write(self.read() - other) __imul__ = lambda self, other: self.write(self.read() * other) - __idiv__ = lambda self, other: self.write(self.read() / other) + __idiv__ = lambda self, other: self.write(old_div(self.read(), other)) __imod__ = lambda self, other: self.write(self.read() % other) __ipow__ = lambda self, other: self.write(self.read() ** other) __iand__ = lambda self, other: self.write(self.read() & other) @@ -2990,7 +3032,7 @@ def check(self): def read(self): self.check() if program.curr_block != self.last_write_block: - self.register = library.load_mem(self.address, self.value_type) + self.register = Compiler.library.load_mem(self.address, self.value_type) self.last_write_block = program.curr_block return self.register @@ -3128,7 +3170,7 @@ def reveal(self): return NamedTuple -import library +import Compiler.library class cintArray(Array): diff --git a/Compiler/util.py b/Compiler/util.py index 5a6e0aac..2e684534 100644 --- a/Compiler/util.py +++ b/Compiler/util.py @@ -1,5 +1,15 @@ +from __future__ import print_function +from __future__ import division +from builtins import range +from past.utils import old_div import math import operator +from functools import reduce +import sys + +if sys.version[0] == "3": + # If we're in python3, integers have unlimited size + long = int def format_trace(trace, prefix=' '): if trace is None: @@ -77,7 +87,7 @@ def if_else(cond, a, b): return b return cond.if_else(a, b) except: - print cond, a, b + print(cond, a, b) raise def cond_swap(cond, a, b): @@ -97,8 +107,8 @@ def tree_reduce(function, sequence): if n == 1: return sequence[0] else: - reduced = [function(sequence[2*i], sequence[2*i+1]) for i in range(n/2)] - return tree_reduce(function, reduced + sequence[n/2*2:]) + reduced = [function(sequence[2*i], sequence[2*i+1]) for i in range(old_div(n,2))] + return tree_reduce(function, reduced + sequence[old_div(n,2*2):]) def or_op(a, b): return a + b - a * b diff --git a/Programs/test_array/test_array.mpc b/Programs/test_array/test_array.mpc index 59dd204c..9b8996dc 100644 --- a/Programs/test_array/test_array.mpc +++ b/Programs/test_array/test_array.mpc @@ -2,7 +2,7 @@ for k in range(10): for t in cint, sint: a = Array(10, t) - print len(a) + print(len(a)) for i,j in enumerate(a): a[i] = j + i diff --git a/Programs/test_fix_array/test_fix_array.mpc b/Programs/test_fix_array/test_fix_array.mpc index 23387f3c..e427a4ba 100644 --- a/Programs/test_fix_array/test_fix_array.mpc +++ b/Programs/test_fix_array/test_fix_array.mpc @@ -2,7 +2,7 @@ for k in range(10): for t in cfix, sfix: a = t.Array(10) - print len(a) + print(len(a)) for i,j in enumerate(a): a[i] = j + i