def visit_Compare(self, node): if __debug__: state.log.debug("infer %s", dump(node, True, True)) if len(node.comparators) > 2: raise TastySyntaxError( "tastyc is not yet ready for more than 2 comparision items") left_node = node.left right_node = node.comparators[0] node.dims = list() node.bit_lengths = list() node.input_types = list() node.signeds = list() node.methodname = bases.CMPOP_METHODS[type(node.ops[0])] annotate_item_of_node(self, left_node, node, False) annotate_item_of_node(self, right_node, node) node_type = left_node.return_info[0]["type"] node.return_info = node_type.returns(node.methodname, node.input_types, node.bit_lengths, node.dims, node.signeds) node.initial_info = node.left.return_info[0]
def visit_Import(self, node): #state.log.debug("\nQualificator %s", dump(node, True, True)) for _alias in node.names: if _alias.name == "tasty.types": raise TastySyntaxError("Found unallowed import statement: " \ "'import tasty.types' at line %r. " \ "Please delete this statement and rewrite your protocol " \ "for direct usage of tasty types." % node.lineno) if _alias.name == "tasty.types.conversions": raise TastySyntaxError("Found unallowed import statement: " \ "'import tasty.types.conversions' at line %r. " \ "Please delete this statement." % node.lineno) if _alias.name == "tasty.types.driver": raise TastySyntaxError("Found unallowed import statement: " \ "'import tasty.types.driver' at line %r. " \ "Please delete this statement." % node.lineno)
def map_inputs(self, inval, inmap): """ first sanitize inputs, in the end, inval should be a list of input values and inmap should be a list of the coresponding input names: inval = dict, inmap = None: => Create inmap list and fill inval with correct values inval = list, inmap = list => everything fine inval = list, inmap = none => inmap = self.inputs then map the inputs in the order the circuit expects it """ def do_map(c, inval, inmap): indict = {} # drop inputs with 0 input-wires c = [x for x in c if x[0]] for pos, i in enumerate(c): indict[i[1]] = (pos, i[0]) ret = [None for i in xrange(len(c))] for val, m in zip(inval, inmap): ret[indict[m][0]] = val return ret c = self.circuit.inputs() # FIXME: @Immo: this is br0ken -> "inlist" unknown if isinstance(inval, dict): inmap = inval.keys() inval = [inval[i] for i in ilist] elif iter(inval): inval = tuple(inval) if not inmap: if not self.inputs: raise TastySyntaxError("No input mapping specified. " \ "You must either specify it on creation or on call!") inmap = self.inputs else: raise TastySyntaxError("Your argument must be a list of inputs") return do_map(c, inval, inmap)
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 handle_target_node(runner, target, value_node): if isinstance(target, Tuple): return_info = value_node.return_info if len(return_info) != len(target.elts): raise SyntaxError("wrong number of type " \ "information records provided") for ix, i in enumerate(target.elts): i_fqnn = get_fqnn(i) runner.symbol_table.add_symbol(i_fqnn, kwargs=return_info[ix], lineno=target.lineno, colno=target.col_offset) elif (isinstance(target, Attribute) or isinstance(target, Name) or isinstance(target, Subscript)): fqnn = get_fqnn(target) try: kwargs = value_node.return_info[0] except AttributeError: kwargs = dict() value_node_rec = value_node.return_info[0] try: value_fqnn = get_fqnn(value_node) if value_fqnn[0] != fqnn[0]: raise TastySyntaxError( "Syntax error at line %d: for sending and/or conversion please use the tasty operator '<<='" % target.lineno) except FqnnError: pass if hasattr(value_node, "bitlen_not_finished"): runner.nodes_without_bitlen[fqnn] = value_node if hasattr(value_node, "signed_not_finished"): runner.nodes_without_signed[fqnn] = value_node if isinstance(target, Subscript): try_finish_bitlenless(runner, fqnn[:2], kwargs["bitlen"]) try_finish_signed(runner, fqnn[:2], kwargs["signed"]) if hasattr(value_node, "tasty_function"): kwargs["tasty_function"] = value_node.tasty_function try: runner.symbol_table.add_symbol(fqnn, kwargs=kwargs, lineno=target.lineno, colno=target.col_offset) except TastySyntaxError, e: if state.config.verbose >= 2: state.log.exception(e)
def Plain_Garbled_send(src, dst, bitlen, dim, signed, force_bitlen=None, force_signed=None): _sendcost(bitlen * (state.config.symmetric_security_parameter + 1)) if isclient(): raise TastySyntaxError("Encrypting to Garbled and Sending to Server does not make sense") if state.precompute: tmp = Garbled(val=src, bitlen=bitlen, signed=signed) state.active_party.push_tmpattr(tmp) else: tmp = state.active_party.pop_tmpattr() tmp = Garbled(val=src, bitlen=bitlen, signed=signed) _sender_copy(tmp, dst) # attaches implicitly here _send(tmp)
def affects(methodname, input_types, role): """Used by tastyc transformation pass""" if __debug__: state.log.debug("GarbledCircuit.affects(%r, %r, %r)", methodname, input_types, role) if methodname == "GarbledCircuit": return Value.S_SETUP | Value.C_SETUP | Value.C_ONLINE if methodname == "__call__": return Value.S_SETUP | Value.C_SETUP | Value.C_ONLINE else: raise TastySyntaxError( "A GarbledCircuit can only be created and evaluated")
def map_outputs(self, outputs, omap): # o is in form ((owires, oname, otype), (owires, oname, otype)...) o = self.circuit.outputs() odict = {} for pos, i in enumerate(o): odict[i[1]] = (pos) if not omap: if not self.outputs: raise TastySyntaxError("You must specify output order either " \ "on creation or on call") omap = self.outputs return tuple(outputs[odict[i]] for i in omap)
def Paillier_Garbled_receive(src, dst, bitlen, dim, signed, force_bitlen=None, force_signed=None): if force_bitlen is not None: bitlen = force_bitlen if force_signed is not None: signed = force_signed p = partyAttribute if not isclient(): raise TastySyntaxError("Conversion from Homomorphic to Garbled from Client to Server does not make sense") masklen = bitlen + state.config.symmetric_security_parameter if state.precompute: # receive garbled Mask mgm = _receive(src, dst) mgm._bit_length = bitlen state.active_party.push_tmpattr(mgm) # prepare for creation of garbled masked plain value mgv = Garbled(bitlen = bitlen, val=p, signed=False) state.active_party.push_tmpattr(mgv) # prepare addition circuit to remove the mask ret = mgv.dropmsb_sub(mgm) # save shadow copy of resulting Garbled _set_dst(src, dst, ret) ret.set_bit_length(bitlen) # avoid warnings here, in online phase this is correct ret._signed = False else: mgm = state.active_party.pop_tmpattr() state.active_party._tmp_ = state.active_party.pop_tmpattr() # get the masked Homomorphic hval = _receive() hval._bit_length = masklen # decrypt the masked Homomorphic mpv = Unsigned(val=hval) mpv._value &= ((1<<bitlen)-1) if mpv.signed(): raise NotImplementedError() mpv.set_bit_length(bitlen) # convert plain masked value into Garbled state.active_party._tmp_ = Garbled(val=mpv, bitlen=bitlen, signed=signed) # deblind the garbled value ret = state.active_party._tmp_.dropmsb_sub(mgm) # tasty calculates theoretical worst case bitlengths. Since we know better, # we can safely overwrite that _set_dst(src, dst, ret) ret.set_bit_length(bitlen) ret._signed = hval.signed()
def get_fqnn(node): """returns the fully qualified node name, but as a tuple e.g: None, 'foo' -> foo (fqnn via Name node) server, 'foo' -> server.foo (fqnn via Attribute node) None, 'foo[0]' -> foo[0] (fqnn via Subscript node) """ if hasattr(node, "fqnn"): return node.fqnn if isinstance(node, BinOp): raise FqnnError("bad style") elif isinstance(node, Attribute): try: fqnn = node.fqnn = node.value.id, node.attr return fqnn except AttributeError: fqnn = node.fqnn = get_fqnn(node.value) return fqnn elif isinstance(node, Name): fqnn = node.fqnn = (node.id, ) return fqnn elif isinstance(node, Subscript): if isinstance(node.value, Name): raise TastySyntaxError( "TASTYL only supports bounded subscriptions") if isinstance(node.slice.value, Name): fqnn = node.fqnn = (node.value.value.id, node.value.attr, node.slice.value.id) return fqnn elif isinstance(node.slice.value, Num): fqnn = node.fqnn = (node.value.value.id, node.value.attr, node.slice.value.n) return fqnn else: raise FqnnError( "Error in line %d: fqnn for type '%s' cannot be evaluated" % (node.lineno, type(node))) else: #if state.config.verbose >= 2: #state.log.error("fqnn for node type '%s' cannot be evaluated" % #type(node)) #state.log.error(dump(node, True, True)) raise FqnnError("Error in line %d: fqnn for type '%s' " \ "cannot be evaluated" % (node.lineno, type(node)))
def visit_ImportFrom(self, node): #state.log.debug("\nQualificator %s", dump(node, True, True)) if node.module == "tasty.types": for _alias in node.names: if _alias.name == "*": bases.TastyCBase.imports.add("types") elif _alias.name == "conversions": bases.TastyCBase.imports.add("conversions") elif _alias.name == state.config.driver_name: raise TastySyntaxError("Found unallowed import statement: " \ "'from tasty.types import driver' at line %r. " \ "Please delete this statement." % node.lineno) if node.module == "tasty.types.driver": for _alias in node.names: if _alias.name == "IODriver": bases.TastyCBase.imports.add("IODriver") elif _alias.name == "TestDriver": bases.TastyCBase.imports.add("TestDriver")
def PaillierVec_GarbledVec_receive(src, dst, source_bitlen, source_dim, signed, force_bitlen=None, force_signed=None): p = partyAttribute if force_bitlen and (force_signed or (signed and not force_signed == False)): raise NotImplementedError("forcing bitlen on signeds is not supported now") if force_bitlen: source_bitlen = force_bitlen overallbitlen = reduce(operator.mul, source_dim, 1) * source_bitlen cpc = state.config.asymmetric_security_parameter - state.config.symmetric_security_parameter - 1 chunksize = (cpc - 1) / source_bitlen chunkpayloadbits = chunksize * source_bitlen chunks = (overallbitlen - 1) / chunkpayloadbits + 1 lastchunksize = overallbitlen % (chunksize * source_bitlen) if lastchunksize: chunksizes = (chunks - 1) * (chunkpayloadbits, ) + (lastchunksize, ) masks = nogen(get_randomm(0, 2**(chunkpayloadbits + state.config.symmetric_security_parameter) - 1, chunks - 1)) + (mpz(rand.randint(0, 2**(lastchunksize + state.config.symmetric_security_parameter) - 1)),) else: chunksizes = chunks * (chunkpayloadbits, ) masks = nogen(get_randomm(0, 2**(chunkpayloadbits + state.config.symmetric_security_parameter)- 1, chunks)) if state.precompute: if force_signed is not None: signed = force_signed # receive garbled Mask mgms = _receive(src, dst) for mgm, size in zip(mgms, chunksizes): mgm._bit_length = size # prepare for creation of garbled masked plain value state.active_party.push_tmpval(mgms) # precompute first chunkpayloadbits for the garbled masked value mgvs = [] for i in chunksizes: mgv = Garbled(bitlen=i, val=p, signed=False) state.passive_party.push_tmpattr(mgv) mgvs.append(mgv) # precompute the unmasking and unpacking rets = [] for mgv, mgm, chunksize in zip (mgvs, mgms, chunksizes): ret = mgv.unpack(mgm, source_bitlen, chunksize, signed) state.active_party.push_tmpattr(ret) rets.extend(ret) rets.reverse() vec = GarbledVec(bitlen=source_bitlen, dim=source_dim, val=rets, signed=signed) # save shadow copy of resulting GarbledVec _set_dst(src, dst, vec) else: # online phase if force_signed is not None: signed = force_signed if not isclient(): raise TastySyntaxError("Conversion from Homomorphic to Garbled from Client to Server does not make sense") # receive masked homomorphic values mhvs = _receive() for i, chunksize in zip(mhvs, chunksizes): i._bit_length = chunksize # decrypt masked garbled values mvs = nogen(Unsigned(val=i) for i in mhvs) # get the masked garbled values from tmpval-stack mgms = state.active_party.pop_tmpval() # compute first chunksize bits of garbled masked values mgvs = [] for mv, chunksize in zip(mvs, chunksizes): state.passive_party._tmp_ = mgv = state.passive_party.pop_tmpattr() mv._value &= (1<<chunksize) - 1 mv.set_bit_length(chunksize) state.passive_party._tmp_ = Garbled(val=mv, bitlen=chunksize, signed=signed) mgvs.append(state.passive_party._tmp_) # unpacking and unblinding rets = [] for mgm, mgv, chunksize in zip(mgms, mgvs, chunksizes): state.active_party._tmp_ = state.active_party.pop_tmpattr() state.active_party._tmp_ = mgv.unpack(mgm, source_bitlen, chunksize, signed) rets.extend(state.active_party._tmp_) rets.reverse() vec = GarbledVec(bitlen=source_bitlen, dim=source_dim, val=rets, signed = rets[0].signed()) _set_dst(src, dst, vec)
def PaillierVec_GarbledVec_send(src, dst, source_bitlen, source_dim, signed, force_bitlen=None, force_signed=None): if force_bitlen and (force_signed or (signed and not force_signed == False)): raise NotImplementedError("forcing bitlen on signeds is not supported now") if force_bitlen is not None: diff = source_bitlen - force_bitlen source_bitlen = force_bitlen else: diff = 0 p = partyAttribute if not isserver(): raise TastySyntaxError("Conversion from Homomorphic to Garbled from Client to Server does not make sense") # number of maximal bits in content overallbitlen = _dimtimes(source_dim) * source_bitlen # we have asymmetric_security_parameter bits to pack into, but need symmetric_security_parameter bits to blind cpc = state.config.asymmetric_security_parameter - state.config.symmetric_security_parameter - 1 chunksize = cpc / source_bitlen chunkpayloadbits = chunksize * source_bitlen chunks = (overallbitlen - 1) / chunkpayloadbits + 1 lastchunksize = overallbitlen % chunkpayloadbits Homomorphic = tasty.types.Homomorphic HomomorphicVec = tasty.types.HomomorphicVec if lastchunksize: chunksizes = (chunks - 1) * (chunkpayloadbits, ) + (lastchunksize, ) else: chunksizes = chunks * (chunkpayloadbits, ) if state.precompute: if lastchunksize: masks = nogen(get_randomm(0, 2**(chunkpayloadbits + state.config.symmetric_security_parameter) - 1, chunks - 1)) + (mpz(rand.randint(0, 2**(lastchunksize + state.config.symmetric_security_parameter) - 1)),) else: masks = nogen(get_randomm(0, 2**(chunkpayloadbits + state.config.symmetric_security_parameter)- 1, chunks)) if force_signed is not None: signed = force_signed # generate Mask values umasks = nogen(Unsigned(val=v, bitlen=l + state.config.symmetric_security_parameter) for v, l in zip(masks, chunksizes)) # homomorphically encrypt masks hmasks = tuple(tasty.types.Homomorphic(val=mask, signed=False) for mask in umasks) state.active_party.push_tmpval(hmasks) # garble first chunkpayloadbits of the masks (manual construction of garbled! Voodoo!) mgms = [] for mask, chunksize in zip(masks, chunksizes): state.passive_party._tmp_ = Garbled(bitlen=chunksize, signed=False, val=p) zv = Garbled.get_zero_value(state.passive_party._tmp_.gid) state.passive_party._tmp_[:] = plain2garbled(value2bits(mask & (1<<chunksize) - 1, chunksize), zv, state.R) mgms.append(state.passive_party._tmp_) state.passive_party.push_tmpval(mgms) #raise NotImplementedError("COSTS") # _sendcost(chunks * chunksize[0] # send garbled masks to client _send(mgms) # precompute the first chunkpayloadbits for the garbled masked value mgvs = [] for chunksize in chunksizes: mgv = Garbled(bitlen=chunksize, passive=True, val=p, signed=False) state.passive_party.push_tmpattr(mgv) mgvs.append(mgv) # precompute the unmasking and unpacking rets = [] for mgv, mgm, chunksize in zip(mgvs, mgms, chunksizes): ret = mgv.unpack(mgm, source_bitlen, chunksize, signed) state.passive_party.push_tmpattr(ret) rets.extend(ret) rets.reverse() # packing works exactly in the oposite direction then unpacking, so reverse here to get original result back vec = GarbledVec(bitlen=source_bitlen, dim=source_dim, val=rets) # save shadow copy of resulting GarbledVec _set_dst(src, dst, vec) else: # online phase assert signed == src.signed(), "the analyzer disagrees with the typesystems signedness" if force_signed is not None: signed = force_signed if not isserver(): raise TastySyntaxError("Conversion from Homomorphic to Garbled from Client to Server does not make sense") # Pack the values with respecting the force_signed and force_bitlen hmasks = state.active_party.pop_tmpval() if force_signed is not None: # we must change it to the forced sign origsigned = src.signed() src._signed = force_signed for i in src: i._signed = force_signed packed, _, _ = src.pack(-(state.config.symmetric_security_parameter + 1), force_bitlen=force_bitlen) if force_signed is not None: # no change in the source, so revert changes done before pack() src._signed = origsigned for i in src: i._signed = origsigned assert len(packed) == len(hmasks), "packing error (%d packed chunks, but %d expected (%r, %r))"%(len(packed), len(hmasks), hmasks, packed) # mask the packed values for i, j in zip(packed, hmasks): i += j # send packed values to client _send(packed) # retrive garbled masks from tmpval-stack mgms = state.passive_party.pop_tmpval() # passive part for generation of garbled masked values mgvs = [] for chunksize in chunksizes: state.passive_party._tmp_ = state.passive_party.pop_tmpattr() state.passive_party._tmp_ = Garbled(val=p, bitlen=chunksize, passive=True, signed=False) mgvs.append(state.passive_party._tmp_) # passive part of unblinding and unpacking # rets = [] for mgm, mgv, chunksize in zip(mgms, mgvs, chunksizes): state.passive_party._tmp_ = state.passive_party.pop_tmpattr()
def Paillier_Garbled_send(src, dst, bitlen, dim, signed, force_bitlen=None, force_signed=None): if force_bitlen is not None: diff = bitlen - force_bitlen bitlen = force_bitlen else: diff = 0 masklen = bitlen + state.config.symmetric_security_parameter # p = partyAttribute if not isserver(): raise TastySyntaxError("Conversion from Homomorphic to Garbled from Client to Server does not make sense") if state.precompute: if force_signed is not None: signed = force_signed if signed: mask = Unsigned(val=rand.randint(2**bitlen - 1, 2**masklen - 1), bitlen=masklen) # generate the Homomorphic blinding mask and store else: mask = Unsigned(val=rand.randint(0, 2**masklen - 1), bitlen=masklen) hmask = tasty.types.Homomorphic(val=mask, signed=False) state.active_party.push_tmpattr(hmask) # Generate the Garbled Blinding Mask mgm = Garbled(bitlen=bitlen, signed=False, val=p) mgm.plainmask = mask # save the mask to be able to access it in online phase state.passive_party.push_tmpattr(mgm) # save the new Garbled zv = Garbled.get_zero_value(mgm.gid) mgm[:] = plain2garbled(value2bits(mask.get_value() & ((1<<bitlen) - 1), bitlen), zv, state.R) _sendcost(state.config.symmetric_security_parameter * bitlen) _send(mgm) # Precompute the garbled for the masked plain value mgv = Garbled(bitlen=bitlen, passive=True, val=p, signed=False) state.passive_party.push_tmpattr(mgv) # prepare the addition circuit to remove the mask ret = mgv.dropmsb_sub(mgm) # save shadow copy of resulting Garbled _set_dst(src, dst, ret) ret.set_bit_length(bitlen) ret._signed = False # avoid warning here else: assert signed == src.signed(), "the analyzer disagrees with the typesystems signedness" if force_signed is not None: signed = force_signed hmask = state.active_party.pop_tmpattr() mgm = state.passive_party.pop_tmpattr() state.passive_party._tmp_ = state.passive_party.pop_tmpattr() # blind the homomorphic and send to other party hval = src + hmask hval._bit_length -= diff # force_bitlen _sendcost(state.config.asymmetric_security_parameter * 2) _send(hval) # help to encrypt the masked value into Garbled state.passive_party._tmp_ = Garbled(bitlen=masklen + 1, passive=True, val=p, signed=signed) # help removing the mask ret = state.passive_party._tmp_.dropmsb_sub(mgm) # tasty calculates theoretical worst case bitlengths. Since we know better, # we can safely overwrite that _set_dst(src, dst, ret) ret.set_bit_length(bitlen) ret._signed = hval.signed()
def ModularVec_ModularVec_send(src, dst, bitlen, dim, signed, force_bitlen=None, force_signed=None): if force_bitlen is not None or force_signed is not None: raise TastySyntaxError("Modular is always unsigned with bitlength of the asymmetric security parameter") _sendcost(state.config.asymmetric_security_parameter * _dimtimes(dim)) _send(src, dst)
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_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)
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 Plain_send(src, dst, bitlen, dim, signed, force_bitlen=None, force_signed=None): if force_signed is not None: raise TastySyntaxError("use Signed/Unsigned for determination of sign in Plain types") _sendcost(bitlen) _send(src)
def check(self): if self.nodes_without_bitlen: raise TastySyntaxError("Following variables are declared without " \ " bitlen and are not finished by either reassignment or " \ "item assignment: %r" % self.nodes_without_bitlen)