def test_assignment_statement(self): i = Identifier('x') lhs = IdentifierExpr(i) rhs = BooleanLiteralExpr(True) a = AssignmentStatement(lhs, rhs) self.assertIsNotNone(a) self.assertEqual(str(a), 'x = true;') self.assertEqual(a.children(), [lhs, rhs]) self.assertDictEqual(a.names, {}) self.assertIsNone(a.parent)
def visitAssignmentStatement(self, ast: AssignmentStatement): lhs = ast.lhs rhs = ast.rhs if has_side_effects(lhs) or has_side_effects(rhs): ast.before_analysis = ast.before_analysis.separate_all() # visit expression self.visit(ast.lhs) self.visit(ast.rhs) # state after assignment after = ast.before_analysis.copy() recursive_assign(lhs, rhs, after) # save state ast.after_analysis = after
def visitAssignmentStatement(self, ast: AssignmentStatement): if not isinstance(ast.lhs, (TupleExpr, LocationExpr)): raise TypeException("Assignment target is not a location", ast.lhs) expected_type = ast.lhs.annotated_type ast.rhs = self.get_rhs(ast.rhs, expected_type) # prevent modifying final f = ast.function if isinstance(ast.lhs, (IdentifierExpr, TupleExpr)): self.check_final(f, ast.lhs)
def visitAssignmentStatement(self, ast: AssignmentStatement): """Rule (2)""" ast.lhs = self.expr_trafo.visit(ast.lhs) ast.rhs = self.expr_trafo.visit(ast.rhs) modvals = list(ast.modified_values.keys()) if cfg.opt_cache_circuit_outputs and isinstance(ast.lhs, IdentifierExpr) and isinstance(ast.rhs, MemberAccessExpr): # Skip invalidation if rhs is circuit output if isinstance(ast.rhs.member, HybridArgumentIdf) and ast.rhs.member.arg_type == HybridArgType.PUB_CIRCUIT_ARG: modvals = [mv for mv in modvals if mv.target != ast.lhs.target] if isinstance(ast.rhs.member.corresponding_priv_expression, EncryptionExpression): ridf = ast.rhs.member.corresponding_priv_expression.expr.idf else: ridf = ast.rhs.member.corresponding_priv_expression.idf assert isinstance(ridf, HybridArgumentIdf) self.gen._remapper.remap(ast.lhs.target.idf, ridf) if self.gen is not None: # Invalidate circuit value for assignment targets for val in modvals: if val.key is None: self.gen.invalidate_idf(val.target.idf) return ast
def visitAssignmentStatement(self, ast: AssignmentStatement): # NB TODO? Should we optionally disallow writes to variables which are owned by someone else (with e.g. a new modifier) #if ast.lhs.annotated_type.is_private(): # expected_rhs_type = AnnotatedTypeName(ast.lhs.annotated_type.type_name, Expression.me_expr()) # if not ast.lhs.instanceof(expected_rhs_type): # raise TypeException("Only owner can assign to its private variables", ast) if not isinstance(ast.lhs, (TupleExpr, LocationExpr)): raise TypeException("Assignment target is not a location", ast.lhs) expected_type = ast.lhs.annotated_type ast.rhs = self.get_rhs(ast.rhs, expected_type) # prevent modifying final f = ast.function if isinstance(ast.lhs, (IdentifierExpr, TupleExpr)): self.check_final(f, ast.lhs)
def _get_public_key_in_sender_field( self, stmt: Statement, cipher: HybridArgumentIdf, crypto_params: CryptoParams) -> HybridArgumentIdf: """ Ensure the circuit has access to the public key stored in cipher's sender field. Note: This function has side effects on stmt [adds a pre-statement] :param stmt [SIDE EFFECT]: statement in which this private expression occurs :param cipher: HybridArgumentIdf which references the cipher value :return: HybridArgumentIdf which references the key in cipher's sender field (or 0 if none) """ key_t = TypeName.key_type(crypto_params) name = f'{self._in_name_factory.get_new_name(key_t)}_sender' key_idf = self._in_name_factory.add_idf(name, key_t) cipher_payload_len = crypto_params.cipher_payload_len key_expr = KeyLiteralExpr( [cipher.get_loc_expr(stmt).index(cipher_payload_len)], crypto_params).as_type(key_t) stmt.pre_statements.append( AssignmentStatement(key_idf.get_loc_expr(), key_expr)) return key_idf
def visitAssignmentStatement(self, ast: AssignmentStatement): self.visit_child_expressions(ast, ast.children())
def add_assignment_to_circuit(self, ast: AssignmentStatement): """Include private assignment statement in this circuit.""" self.phi.append(CircComment(ast.code())) self._add_assign(ast.lhs, ast.rhs)
def evaluate_stmt_in_circuit(self, ast: Statement) -> AssignmentStatement: """ Evaluate an entire statement privately. This works by turning the statement into an assignment statement where the * lhs is a tuple of all external locations (defined outside statement), which are modified inside the statement * rhs is the return value of an inlined function call expression to a virtual function where body = the statement + return statement \ which returns a tuple of the most recent SSA version of all modified locations Note: Modifying external locations which are not owned by @me inside the statement is illegal (would leak information). Note: At the moment, this is only used for if statements with a private condition. :param ast: the statement to evaluate inside the circuit :return: AssignmentStatement as described above """ astmt = ExpressionStatement(NumberLiteralExpr(0)) for var in ast.modified_values: if var.in_scope_at(ast): astmt = AssignmentStatement(None, None) break astmt.before_analysis = ast.before_analysis # External values written inside statement -> function return values ret_params = [] for var in ast.modified_values: if var.in_scope_at(ast): # side effect affects location outside statement and has privacy @me assert ast.before_analysis.same_partition( var.privacy, Expression.me_expr()) assert isinstance( var.target, (Parameter, VariableDeclaration, StateVariableDeclaration)) t = var.target.annotated_type.zkay_type if not t.type_name.is_primitive_type(): raise NotImplementedError( 'Reference types inside private if statements are not supported' ) ret_t = AnnotatedTypeName(t.type_name, Expression.me_expr(), t.homomorphism) # t, but @me ret_param = IdentifierExpr(var.target.idf.clone(), ret_t).override(target=var.target) ret_param.statement = astmt ret_params.append(ret_param) # Build the imaginary function fdef = ConstructorOrFunctionDefinition( Identifier('<stmt_fct>'), [], ['private'], [ Parameter([], ret.annotated_type, ret.target.idf) for ret in ret_params ], Block([ast, ReturnStatement(TupleExpr(ret_params))])) fdef.original_body = fdef.body fdef.body.parent = fdef fdef.parent = ast # inline "Call" to the imaginary function fcall = FunctionCallExpr( IdentifierExpr('<stmt_fct>').override(target=fdef), []) fcall.statement = astmt ret_args = self.inline_function_call_into_circuit(fcall) # Move all return values out of the circuit if not isinstance(ret_args, TupleExpr): ret_args = TupleExpr([ret_args]) for ret_arg in ret_args.elements: ret_arg.statement = astmt ret_arg_outs = [ self._get_circuit_output_for_private_expression( ret_arg, Expression.me_expr(), ret_param.annotated_type.homomorphism) for ret_param, ret_arg in zip(ret_params, ret_args.elements) ] # Create assignment statement if ret_params: astmt.lhs = TupleExpr( [ret_param.clone() for ret_param in ret_params]) astmt.rhs = TupleExpr(ret_arg_outs) return astmt else: assert isinstance(astmt, ExpressionStatement) return astmt