def try_rehom(rhs: Expression, expected_type: AnnotatedTypeName): if rhs.annotated_type.is_public(): raise ValueError( 'Cannot change the homomorphism of a public value') if rhs.annotated_type.is_private_at_me(rhs.analysis): # The value is @me, so we can just insert a ReclassifyExpr to change # the homomorphism of this value, just like we do for public values. return TypeCheckVisitor.make_rehom(rhs, expected_type) if isinstance(rhs, ReclassifyExpr) and not isinstance(rhs, RehomExpr): # rhs is a valid ReclassifyExpr, i.e. the argument is public or @me-private # To create an expression with the correct homomorphism, # just change the ReclassifyExpr's output homomorphism rhs.homomorphism = expected_type.homomorphism elif isinstance(rhs, PrimitiveCastExpr): # Ignore primitive cast & recurse rhs.expr = TypeCheckVisitor.try_rehom(rhs.expr, expected_type) elif isinstance(rhs, FunctionCallExpr) and isinstance(rhs.func, BuiltinFunction) and rhs.func.is_ite() \ and rhs.args[0].annotated_type.is_public(): # Argument is public_cond ? true_val : false_val. Try to rehom both true_val and false_val rhs.args[1] = TypeCheckVisitor.try_rehom(rhs.args[1], expected_type) rhs.args[2] = TypeCheckVisitor.try_rehom(rhs.args[2], expected_type) else: raise TypeMismatchException(expected_type, rhs.annotated_type, rhs) # Rehom worked without throwing, change annotated_type and return rhs.annotated_type = rhs.annotated_type.with_homomorphism( expected_type.homomorphism) return rhs
def replace_expr(old_expr: Expression, new_expr: Expression, copy_type: bool = False): """ Copies over ast common ast attributes and reruns, parent setter, symbol table, side effect detector """ _replace_ast(old_expr, new_expr) if copy_type: new_expr.annotated_type = old_expr.annotated_type return new_expr
def _get_circuit_output_for_private_expression( self, expr: Expression, new_privacy: PrivacyLabelExpr, homomorphism: Homomorphism) -> LocationExpr: """ Add evaluation of expr to the circuit and return the output HybridArgumentIdf corresponding to the evaluation result. Note: has side effects on expr.statement (adds pre_statement) :param expr: [SIDE EFFECT] expression to evaluate :param new_privacy: result owner (determines encryption key) :return: HybridArgumentIdf which references the circuit output containing the result of expr """ is_circ_val = isinstance(expr, IdentifierExpr) and isinstance( expr.idf, HybridArgumentIdf ) and expr.idf.arg_type != HybridArgType.PUB_CONTRACT_VAL is_hom_comp = isinstance(expr, FunctionCallExpr) and isinstance( expr.func, BuiltinFunction ) and expr.func.homomorphism != Homomorphism.NON_HOMOMORPHIC if is_hom_comp: # Treat a homomorphic operation as a privately evaluated operation on (public) ciphertexts expr.annotated_type = AnnotatedTypeName.cipher_type( expr.annotated_type, homomorphism) if is_circ_val or expr.annotated_type.is_private( ) or expr.evaluate_privately: priv_result_idf = self._evaluate_private_expression(expr) else: # For public expressions which should not be evaluated in private, only the result is moved into the circuit priv_result_idf = self.add_to_circuit_inputs(expr) private_expr = priv_result_idf.get_idf_expr() t_suffix = '' if isinstance(expr, IdentifierExpr) and not is_circ_val: t_suffix += f'_{expr.idf.name}' if isinstance(new_privacy, AllExpr) or expr.annotated_type.type_name.is_cipher(): # If the result is public, add an equality constraint to ensure that the user supplied public output # is equal to the circuit evaluation result tname = f'{self._out_name_factory.get_new_name(expr.annotated_type.type_name)}{t_suffix}' new_out_param = self._out_name_factory.add_idf( tname, expr.annotated_type.type_name, private_expr) self._phi.append(CircEqConstraint(priv_result_idf, new_out_param)) out_var = new_out_param.get_loc_expr().explicitly_converted( expr.annotated_type.type_name) else: # If the result is encrypted, add an encryption constraint to ensure that the user supplied encrypted output # is equal to the correctly encrypted circuit evaluation result new_privacy = self._get_canonical_privacy_label( expr.analysis, new_privacy) privacy_label_expr = get_privacy_expr_from_label(new_privacy) cipher_t = TypeName.cipher_type(expr.annotated_type, homomorphism) tname = f'{self._out_name_factory.get_new_name(cipher_t)}{t_suffix}' enc_expr = EncryptionExpression(private_expr, privacy_label_expr, homomorphism) new_out_param = self._out_name_factory.add_idf( tname, cipher_t, enc_expr) crypto_params = cfg.get_crypto_params(homomorphism) self._ensure_encryption(expr.statement, priv_result_idf, new_privacy, crypto_params, new_out_param, False, False) out_var = new_out_param.get_loc_expr() # Add an invisible CircuitComputationStatement to the solidity code, which signals the offchain simulator, # that the value the contained out variable must be computed at this point by simulating expression evaluation expr.statement.pre_statements.append( CircuitComputationStatement(new_out_param)) return out_var