Example #1
0
 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)
Example #2
0
    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
Example #3
0
    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)
Example #4
0
    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
Example #5
0
    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)
Example #6
0
    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
Example #7
0
 def visitAssignmentStatement(self, ast: AssignmentStatement):
     self.visit_child_expressions(ast, ast.children())
Example #8
0
 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)
Example #9
0
    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