def visit_Compare(self, node): # state.log.debug("\ncosts %s", dump(node)) fqnn = bases.get_fqnn(node.left) party_name = fqnn[0] if party_name == self.passive_name: passive = True role = self.passive_role else: passive = False role = self.active_role try: left_symbol_record = self.symbol_table.identify(fqnn) left_kwargs = left_symbol_record["kwargs"] except UnknownSymbolError: left_kwargs = node.left.return_info[0] left_type = left_kwargs["type"] left_bitlen = left_kwargs["bitlen"] left_dim = left_kwargs["dim"] left_signed = left_kwargs["signed"] try: right_fqnn = bases.get_fqnn(node.comparators[0]) right_symbol_record = self.symbol_table.identify(right_fqnn) right_kwargs = right_symbol_record["kwargs"] except FqnnError, e: right_kwargs = node.comparators[0].return_info[0]
def visit_For(self, node): """Creates a symbol_table entry for node.target and visits each body node. TASK: metatasty: Use stacked symbol_tables to store 'node.target' symbol table entry. This would give much more symbol_record accuracy. """ if __debug__: state.log.debug("\ninfer %s", dump(node, True, True)) fqnn = get_fqnn(node.target) target_rec = dict() if isinstance(node.iter, Call): if isinstance(node.iter.func, Name): if isinstance(node.iter.args[0], Num): target_rec["type"] = types.Unsigned target_rec["bitlen"] = mpz( node.iter.args[0].n).bit_length() target_rec["dim"] = [1] target_rec["signed"] = False else: arg_fqnn = get_fqnn(node.iter.args[0]) symbol_record = self.symbol_table.identify(arg_fqnn) target_rec = symbol_record["kwargs"] else: raise TastySyntaxError( "'for' not handled for iteration node type %s" % type(node.iter.func)) elif isinstance(node.iter, Attribute): arg_fqnn = get_fqnn(node.iter) symbol_record = self.symbol_table.identify(arg_fqnn) kwargs = symbol_record["kwargs"] node.iter.return_info = (kwargs, ) iter_node_type = kwargs["type"] bit_lengths = (kwargs["bitlen"], ) dims = (kwargs["dim"], ) signeds = (kwargs["signed"], ) node.target.return_info = iter_node_type.returns( "__getitem__", tuple(), bit_lengths, dims, signeds) target_rec = node.target.return_info[0] else: raise NotImplementedError( "'for' not handled for iteration node type %s" % type(node.iter)) self.symbol_table.add_symbol(fqnn, kwargs=target_rec, lineno=node.lineno, colno=node.col_offset) #self.symbol_table.dump() for i in node.body: self.visit(i)
def visit_Call(self, node): if __debug__: state.log.debug("\ntype completion %s", dump(node)) self.visit(node.func) if hasattr(node, "call_type") and node.call_type == CALL_TYPE_CTOR: val = node.keywords_map.get("val") if val: if not isinstance(val.value, Attribute): return node fqnn = get_fqnn(val.value) if fqnn not in self.symbol_table: symbol_record = self.global_table.identify(fqnn) kwargs = symbol_record["kwargs"] symbol_type = kwargs["type"] node.keywords_map["val"].value = Call( func=Name(id=symbol_type.__name__), args=[], kwargs=None, starargs=None, keywords=[ keyword(arg="bitlen", value=Num(n=kwargs["bitlen"])), keyword(arg="dim", value=Num(n=kwargs["dim"])), keyword(arg="signed", value=Name(id=str(kwargs["signed"]))), keyword(arg="passive", value=Name(id="True")), keyword(arg="empty", value=Name(id="True")) ]) return node
def check_simple_affects(self, node): if isinstance(node, Attribute): fqnn = get_fqnn(node) symbol_record = self.symbol_table.identify(fqnn) return symbol_record["bitmask"] else: raise NotImplementedError("Not implemented for %r" % type(node))
def visit_If(self, node): if not bases.has_parent_node(node, bases.TastyCBase.protocol_name): return if isinstance(node.test, Attribute): symbol_record = self.symbol_table.identify(get_fqnn(node.test)) node.test.return_info = (symbol_record["kwargs"], ) else: self.visit(node.test) if not hasattr(node.test, "return_info"): raise NotImplementedError( "Inferency of test component of 'if' code not implemented" % type(node.test)) for i in node.body: self.visit(i) while True: else_ = node.orelse num_items = len(else_) if num_items == 1: if isinstance(else_[0], If): node = else_[0] for i in node.body: self.visit(i) else: for i in else_: self.visit(i) break else: break
def visit_Assign_2nd_pass(self, node): #state.log.debug("\nconstant propagation 2nd pass %s", #dump(node, True, True)) target = node.targets[0] if isinstance(target, Name): fqnn = get_fqnn(target) if fqnn in self.propagated_symbols: return return node
def visit_BinOp(self, node): if isinstance(node.left, Attribute): fqnn = get_fqnn(node.left) if fqnn not in self.symbol_table: symbol_record = self.global_table.identify(fqnn) kwargs = symbol_record["kwargs"] symbol_type = kwargs["type"] node.left = Call(func=Name(id=symbol_type.__name__), args=[], kwargs=None, starargs=None, keywords=[ keyword(arg="bitlen", value=Num(n=kwargs["bitlen"])), keyword(arg="dim", value=Num(n=kwargs["dim"])), keyword( arg="signed", value=Name(id=str(kwargs["signed"]))), keyword(arg="passive", value=Name(id="True")), keyword(arg="empty", value=Name(id="True")) ]) if isinstance(node.right, Attribute): fqnn = get_fqnn(node.right) if fqnn not in self.symbol_table: symbol_record = self.global_table.identify(fqnn) symbol_type = symbol_record["node_type"] kwargs = symbol_record["kwargs"] node.right = Call( func=Name(id=symbol_type.__name__), args=[], kwargs=None, starargs=None, keywords=[ keyword(arg="bitlen", value=Num(n=kwargs["bitlen"])), keyword(arg="dim", value=Num(n=kwargs["dim"])), keyword(arg="signed", value=Name(id=str(kwargs["signed"]))), keyword(arg="passive", value=Name(id="True")), keyword(arg="empty", value=Name(id="True")) ]) return node
def visit_Assign(self, node): """Only assignments of global aka party unbounded symbol/variable nodes gets analyzed, stored and annotated""" if isinstance(node.value, Num): #state.log.debug("symbolize constant %s", dump(node, True, True)) for target in node.targets: self.symbol_table.add_symbol(get_fqnn(target), kwargs=eval_num_arg(node.value), lineno=target.lineno, colno=target.col_offset)
def visit_Attribute(self, node): try: fqnn = get_fqnn(node) if fqnn[0] == self.active_name: node.role = self.active_role node.passive = False else: node.role = self.passive_role node.passive = True except Exception: pass
def visit_Subscript(self, node): self.visit(node.value) if hasattr(node.value, "role"): node.role = node.value.role node.passive = node.value.passive else: fqnn = get_fqnn(node) if fqnn[0] == self.active_name: node.role = self.active_role node.passive = False else: node.role = self.passive_role node.passive = True
def visit_Expr(self, node): #state.log.debug("\nattribute propagator %s", dump(node, True, True)) if (isinstance(node.value, Call) and isinstance(node.value.func, Attribute)): fqnn = get_fqnn(node.value.func) if fqnn[0] == self.active_name: node.role = self.active_role node.passive = False else: node.role = self.passive_role node.passive = True set_inherited_attributes(node, ("role", "passive"))
def visit_Assign(self, node): if not has_parent_node(node, bases.TastyCBase.protocol_name): return node if __debug__: state.log.debug("prune %s", dump(node, True, True)) node.value = self.visit(node.value) if not node.value or self.check_remove(node): for target in node.targets: if (isinstance(target, Attribute) or isinstance(target, Subscript)): self.symbol_table.remove_symbol(get_fqnn(target)) elif isinstance(target, Tuple): for item in target.elts: self.symbol_table.remove_symbol(get_fqnn(item)) elif isinstance(target, Name): self.symbol_table.remove_symbol(get_fqnn(target)) else: raise NotImplementedError("pruning of assign " \ "for node %r not yet implemented" % type(target)) return return node
def visit_tasty_func_call(self, node): if __debug__: state.log.debug("\ninfer tasty func call %d %s", id(node), dump(node, True, True)) if isinstance(node.func, Name): fqnn = get_fqnn(node.func) symbol_record = self.symbol_table.identify(fqnn) # checking for tasty function kwargs = symbol_record["kwargs"] node.tasty_function = kwargs["tasty_function"] kwargs = symbol_record["kwargs"] node_type = kwargs["type"] node.initial_info = kwargs elif isinstance(node.func, Call): self.visit(node.func) node.tasty_function = node.func.tasty_function else: raise UnknownSymbolError() # than this is not a tasty func for i in node.args: self.visit(i) retrieve_node_args(node) node.methodname = "__call__" node.call_type = CALL_TYPE_TASTY_FUNC_CALL node.input_types = list() node.bit_lengths = list() node.dims = list() node.signeds = list() for arg in node.args: ri = arg.return_info[0] node.input_types.append(ri["type"]) node.bit_lengths.append(ri["bitlen"]) node.dims.append(ri["dim"]) node.signeds.append(ri["signed"]) node.return_info = node.tasty_function.returns(node.methodname, node.input_types, node.bit_lengths, node.dims, node.signeds) if isinstance(node.parent, Attribute): copy_type_info(node.parent, node) elif isinstance(node.func, Call): # directly called tasty functions after instantiation node.initial_info = node.func.return_info[0]
def visit_Name(self, node): #state.log.debug("\nconstant propagation %s", dump(node, True, True)) if (isinstance(node.parent, Attribute) or node.id in tasty.tastyc.analyzation._cost_class_names or node.id in (self.active_name, self.passive_name)): return node try: fqnn = get_fqnn(node) symbol_record = self.symbol_table.identify(fqnn) node_kwargs = symbol_record["kwargs"] except Exception, e: #if state.config.verbose >= 2: #state.log.exception(e) pass
def visit_Assign(self, node): if __debug__: state.log.debug("\npass dispatch pre %s", dump(node, True, True)) if not has_parent_node(node, bases.TastyCBase.protocol_name): return self.visit(node.value) if isinstance(node.value, Attribute): symbol_record = self.symbol_table.identify(get_fqnn(node.value)) symbol_record[ "bitmask"] = node.bitmask = Value.S_ONLINE if node.role else Value.C_ONLINE elif isinstance(node.value, Num): node.bitmask = 15 else: node.bitmask = node.value.bitmask assert hasattr(node, "bitmask")
def visit_Subscript(self, node): if not has_parent_node(node, self.protocol_name): return if __debug__: state.log.debug("\ninfer %d %s", id(node), dump(node, True, True)) fqnn = get_fqnn(node.value) symbol_record = self.symbol_table.identify(fqnn) kwargs = symbol_record["kwargs"] node_type = kwargs["type"] node.initial_info = kwargs node.input_types = tuple() node.bit_lengths = (kwargs["bitlen"], ) node.dims = (kwargs["dim"], ) node.signeds = (kwargs["signed"], ) node.methodname = "__getitem__" node.return_info = node_type.returns(node.methodname, node.input_types, node.bit_lengths, node.dims, node.signeds)
def visit_constructor(self, node): """here we inspect constructor invocations.""" if __debug__: state.log.debug("\ninfer ctor %s", dump(node, True, True)) node.call_type = CALL_TYPE_CTOR node.methodname = node.node_type.__name__ self.visit(node.func) for i in node.keywords: self.visit(i) if hasattr(node, "keywords_data"): raise InternalError( "trying to overwrite keywords_data attribute twice") # keyword name -> object # real objects of ast representation node.keywords_data = dict() # keyword name -> keyword node # used for fast access to keyword nodes node.keywords_map = dict() if node.args: raise TastySyntaxError( "Tasty type constructors must not use positional arguments") for ix, kw in enumerate(node.keywords): value = kw.value key = kw.arg node.keywords_map[key] = kw node.keywords_data[key] = value if isinstance(value, Num): evaled = eval_num_arg(value) node.keywords_data[key] = evaled["val"] evaled["type"] = node.node_type kw.return_info = (evaled, ) elif isinstance(value, Attribute): symbol_record = self.symbol_table.identify(get_fqnn(value)) kwargs = copy.deepcopy(symbol_record["kwargs"]) kw.return_info = (kwargs, ) elif isinstance(value, List): eval_value = eval_arg(value) node.keywords_data[key] = eval_value["val"] kw.return_info = (eval_value, ) elif isinstance(value, Tuple): eval_value = eval_arg(value) node.keywords_data[key] = eval_value["val"] kw.return_info = (eval_value, ) elif isinstance(value, Name): if value.id == "None": raise TastySyntaxError( "'None' not allowed as constructor argument") elif value.id == "True": kw.return_info = ({ "type": bool, "bitlen": None, "dim": None, "signed": None }, ) node.keywords_data[key] = True elif value.id == "False": kw.return_info = ({ "type": bool, "bitlen": None, "dim": None, "signed": None }, ) node.keywords_data[key] = False else: raise NotImplementedError("argument %r not handled" % value.id) elif (isinstance(value, UnaryOp) or isinstance(value, BinOp) or isinstance(value, BoolOp) or isinstance(value, Subscript)): kw.return_info = kw.value.return_info else: raise NotImplementedError("unhandled node type %s" % type(value)) val = node.keywords_map.get("val") if val: kwargs = val.return_info[0] for k, v in kwargs.iteritems(): if (k not in node.keywords_data and k not in ("force_signed", "force_bitlen")): node.keywords_data[k] = v if "dim" not in node.keywords_data: if (issubclass(node.node_type, types.PlainType) or issubclass(node.node_type, types.GarbledType) or issubclass(node.node_type, types.HomomorphicType)): node.keywords_data["dim"] = [1] elif issubclass(node.node_type, types.Vec): # otherwise inspect val kwargs for dims val_node = node.keywords_data["val"] if isinstance(val, Attribute): symbol_record = self.symbol_table.identify( get_fqnn(val_node)) kwargs = symbol_record["kwargs"] node.keywords_data["dim"] = kwargs["dim"] else: raise NotImplementedError("not implemented for %s" % type(val)) dim = node.keywords_data["dim"] try: iter(dim) except TypeError: node.keywords_data["dim"] = dim = [dim] except KeyError: raise if "force_bitlen" in node.keywords_data: node.keywords_data["bitlen"] = node.keywords_data["force_bitlen"] if "force_signed" in node.keywords_data: node.keywords_data["signed"] = node.keywords_data["force_signed"] if not "signed" in node.keywords_data: try: val = node.keywords_data["val"] node.keywords_data["signed"] = val.return_info[0]["signed"] except KeyError: node.signed_not_finished = True if "bitlen" not in node.keywords_data: if node.node_type in (types.Modular, types.ModularVec): node.keywords_data["bitlen"] = \ state.config.asymmetric_security_parameter elif issubclass(node.node_type, types.TastyFunction): pass else: #node.keywords_data["bitlen"] = e # the type declaration is not yet completed. Later we must # ensure correct tasty type initialization and set in node # and symbol table if present node.bitlen_not_finished = True if __debug__: state.log.debug("bitlen_not_finished") force_bitlen = node.keywords_data.get("force_bitlen") if force_bitlen: node.keywords_data["bitlen"] = force_bitlen force_signed = node.keywords_data.get("force_signed") if force_signed: node.keywords_data["signed"] = True val_return_rec = None bit_lengths = None dims = None if val: #propagate_kwargs(node) val_return_rec = val.return_info[0] input_types = (val_return_rec["type"], ) bit_lengths = (node.keywords_data["bitlen"], val_return_rec["bitlen"]) dims = (node.keywords_data["dim"], val_return_rec["dim"]) signeds = (node.keywords_data.get("signed"), val_return_rec["signed"]) else: input_types = tuple() bit_lengths = (node.keywords_data.get("bitlen"), ) dims = (node.keywords_data["dim"], ) signeds = (node.keywords_data.get("signed"), None) # in this special case we must populate input_types, bit_lengths, dims # and signeds after calling returns() node.return_info = node.node_type.returns(node.methodname, input_types, bit_lengths, dims, signeds) return_rec = node.return_info[0] if val: node.input_types = (val_return_rec["type"], ) node.bit_lengths = (return_rec["bitlen"], val_return_rec["bitlen"]) node.dims = (return_rec["dim"], val_return_rec["dim"]) node.signeds = (return_rec["signed"], val_return_rec["signed"]) else: node.input_types = tuple() node.bit_lengths = (return_rec["bitlen"], ) node.dims = (return_rec["dim"], ) node.signeds = (return_rec["signed"], ) if isinstance(node.parent, Attribute): copy_type_info(node.parent, node) assert hasattr(node, "return_info") assert hasattr(node, "node_type") assert (isinstance(node.keywords_data, dict)) assert "dim" in node.keywords_data assert type(node.return_info[0]["dim"]) != dict node.initial_info = node.return_info[0]
def visit_method(self, node): """here we inspect function and method calls""" if __debug__: state.log.debug("\ninfer method %d %s", id(node), dump(node, True, True)) node.call_type = CALL_TYPE_METHOD # handling method of party attribute if (isinstance(node.func, Attribute) and isinstance(node.func.value, Attribute)): attribute_symbol_record = self.symbol_table.identify( get_fqnn(node.func.value)) node.func.return_info = node.func.value.return_info = \ (attribute_symbol_record["kwargs"],) self.visit(node.func) for i in node.args: self.visit(i) if hasattr(node, "attr"): if node.attr == "input": node.methodname = "input" elif node.attr == "output": node.methodname = "output" else: raise NotImplementedError() assert hasattr(node, "methodname") return if hasattr(node.func, "attr"): if node.func.attr == "input": cnode = node.func.value node.methodname = "input" if (hasattr(cnode, "call_type") and cnode.call_type == CALL_TYPE_CTOR): add_keyword(cnode, "empty", True) copy_type_info(node, node.func) node.initial_info = cnode.return_info[0] node.input_types = tuple() node.dims = tuple() return elif node.func.attr in ("output", "setup_output"): node.methodname = node.func.attr return retrieve_node_args(node) symbol_table = self.symbol_table # handles methods of bounded party attributes if isinstance(node.func, Attribute): if hasattr(node.func.value, "call_type" ) and node.func.value.call_type == CALL_TYPE_CTOR: attribute_node_type = node.func.value.node_type attribute_kwargs = node.func.value.return_info[0] elif (isinstance(node.func.value, Attribute) or isinstance(node.func.value, Call)): fqnn = find_fqnn(node.func.value) attribute_symbol_record = symbol_table.identify(fqnn) attribute_kwargs = attribute_symbol_record["kwargs"] attribute_node_type = attribute_kwargs["type"] elif isinstance(node.func.value, Subscript): attribute_kwargs = node.func.value.return_info[0] attribute_node_type = attribute_kwargs["type"] node.methodname = methodname = node.func.attr node.input_types = list() node.bit_lengths = [attribute_kwargs["bitlen"]] node.dims = [attribute_kwargs["dim"]] node.signeds = [attribute_kwargs["signed"]] node.input_types.extend( [arg.return_info[0]["type"] for arg in node.args]) node.dims.extend([arg.return_info[0]["dim"] for arg in node.args]) node.bit_lengths.extend( [arg.return_info[0]["bitlen"] for arg in node.args]) node.return_info = attribute_node_type.returns( node.methodname, node.input_types, node.bit_lengths, node.dims, node.signeds) node.initial_info = attribute_kwargs else: raise TastySyntaxError( "expected a method of a subclass of Value or Vec, got '%s'" % type(node.func)) if isinstance(node.parent, Attribute): copy_type_info(node.parent, node) assert hasattr(node, "return_info") assert hasattr(node, "initial_info") assert hasattr(node, "methodname") assert type(node.return_info[0]) == dict assert type(node.initial_info) == dict
def visit_AugAssign(self, node): """ checking for tasty operators with previously undefined targets and annotates them with the type information of the source""" if __debug__: state.log.debug("\ninfer %s", dump(node, True, True)) left_node = node.target right_node = node.value fqnn = get_fqnn(left_node) if isinstance(node.op, LShift): # special treatment, since semantic redefined as sending operator # with optional type conversion if not isinstance(node.target, Attribute): raise TastySyntaxError("Can only send to a party") if node.value.passive: direction = "receive" else: direction = "send" try: # processing bound party attribute, both sides have same type right_fqnn = get_fqnn(right_node) symbol_record = self.symbol_table.identify(right_fqnn) dest_return_rec = symbol_record["kwargs"] dest_type = dest_return_rec["type"] dest_bitlen = dest_return_rec["bitlen"] dest_dim = dest_return_rec["dim"] dest_signed = dest_return_rec["signed"] node.input_types = (dest_type, dest_type) node.bit_lengths = (dest_bitlen, dest_bitlen) node.dims = (dest_dim, dest_dim) node.signeds = (dest_signed, dest_signed) node.return_info = ((dest_type, dest_bitlen, dest_dim, dest_signed), ) node.methodname = "%s_%s_%s" % (dest_type.__name__, dest_type.__name__, direction) except (FqnnError, UnknownSymbolError): if not isinstance(right_node, Call): raise TastySyntaxError("value of tasty operator must be " \ "a constructor call of a type of TASTY or a " \ "bound PartyAttribute, got %r" % type(right_node)) # tasty operator including type conversion self.visit(right_node) node.return_info = right_node.return_info dest_return_rec = right_node.return_info[0] src_node = right_node.keywords_map["val"] src_return_rec = src_node.return_info[0] src_type = src_return_rec["type"] dest_type = dest_return_rec["type"] node.input_types = (dest_return_rec["type"], src_return_rec["type"]) node.bit_lengths = (dest_return_rec["bitlen"], src_return_rec["bitlen"]) node.dims = (dest_return_rec["dim"], src_return_rec["dim"]) node.signeds = (dest_return_rec["signed"], src_return_rec["signed"]) node.methodname = "%s_%s_%s" % (src_type.__name__, dest_type.__name__, direction) try_finish_bitlenless(self, fqnn, dest_return_rec["bitlen"]) try_finish_signed(self, fqnn, dest_return_rec["signed"]) node.initial_info = node.return_info[0] self.symbol_table.add_symbol(fqnn, kwargs=dest_return_rec, lineno=node.lineno, colno=node.col_offset) else: # normal pythonic operator behaviour fqnn = get_fqnn(left_node) node.dims = list() node.bit_lengths = list() node.input_types = list() node.signeds = list() annotate_item_of_node(self, left_node, node, False) annotate_item_of_node(self, right_node, node) node.methodname = bases.AUGASSIGN_METHODS[type(node.op)] node.return_info = left_node.return_info[0]["type"].returns( node.methodname, node.input_types, node.bit_lengths, node.dims, node.signeds) kwargs = node.return_info[0] self.symbol_table.add_symbol(fqnn, kwargs=kwargs, lineno=node.lineno, colno=node.col_offset)