def transform_internal_calls( fcts_with_verification: List[ConstructorOrFunctionDefinition], cgens: Dict[ConstructorOrFunctionDefinition, CircuitHelper]): """ Add required additional args for public calls to functions which require verification. This must be called after compute_transitive_circuit_io_sizes. Whenever a function which requires verification is called, the caller needs to pass along the circuit input and output arrays, as well as the correct start indices for them, such that the callee deserializes/serializes from/into the correct segment of the output/input array. This function thus transforms function calls to functions requiring verification, by adding these additional arguments. This must be done in a second pass, after all function bodies in the contract are fully transformed, since the correct start indices depend on the circuit IO sizes of the caller function (see ZkayTransformer documentation for more information). :param fcts_with_verification: [SIDE EFFECT] All functions which have a circuit associated with them :param cgens: A map from function to circuit """ for fct in fcts_with_verification: circuit = cgens[fct] i, o, p = 0, 0, 0 for fc in circuit.function_calls_with_verification: fdef = fc.func.target fc.sec_start_offset = circuit.priv_in_size + p fc.args += [ IdentifierExpr(cfg.zk_in_name), IdentifierExpr(f'{cfg.zk_in_name}_start_idx').binop( '+', NumberLiteralExpr(circuit.in_size + i)), IdentifierExpr(cfg.zk_out_name), IdentifierExpr(f'{cfg.zk_out_name}_start_idx').binop( '+', NumberLiteralExpr(circuit.out_size + o)) ] i, o, p = i + cgens[fdef].in_size_trans, o + cgens[ fdef].out_size_trans, p + cgens[fdef].priv_in_size_trans assert i == circuit.trans_in_size and o == circuit.trans_out_size and p == circuit.trans_priv_size
def _handle_crement_expr(self, ctx, kind: str): if not self.is_expr_stmt(ctx): raise SyntaxException(f'{kind}-crement expressions are only allowed as statements', ctx, self.code) op = '+' if ctx.op.text == '++' else '-' one = NumberLiteralExpr(1) one.line = ctx.op.line one.column = ctx.op.column + 1 fct = FunctionCallExpr(BuiltinFunction(op).override(line=ctx.op.line, column=ctx.op.column), [self.visit(ctx.expr), one]) fct.line = ctx.op.line fct.column = ctx.op.column + 1 return ast.AssignmentStatement(self.visit(ctx.expr), fct, f'{kind}{ctx.op.text}')
def create_contract_variable(cname: str) -> StateVariableDeclaration: """Create a public constant state variable with which contract with name 'cname' can be accessed""" inst_idf = Identifier(cfg.get_contract_var_name(cname)) c_type = ContractTypeName([Identifier(cname)]) cast_0_to_c = PrimitiveCastExpr(c_type, NumberLiteralExpr(0)) var_decl = StateVariableDeclaration(AnnotatedTypeName(c_type), ['public', 'constant'], inst_idf.clone(), cast_0_to_c) return var_decl
def add_var_decl_to_circuit(self, ast: VariableDeclarationStatement): self.phi.append(CircComment(ast.code())) if ast.expr is None: # Default initialization is made explicit for circuit variables t = ast.variable_declaration.annotated_type.type_name assert t.can_be_private() ast.expr = TypeCheckVisitor.implicitly_converted_to( NumberLiteralExpr(0).override(parent=ast, statement=ast), t.clone()) self.create_new_idf_version_from_value(ast.variable_declaration.idf, ast.expr)
def visitFunctionCallExpr(self, ast: FunctionCallExpr): t = ast.annotated_type.type_name # Constant folding for literal types if isinstance(t, BooleanLiteralType): return replace_expr(ast, BooleanLiteralExpr(t.value)) elif isinstance(t, NumberLiteralType): return replace_expr(ast, NumberLiteralExpr(t.value)) if isinstance(ast.func, BuiltinFunction): # Builtin functions are supported natively by the circuit return self.visit_children(ast) fdef = ast.func.target assert fdef.is_function assert fdef.return_parameters assert fdef.has_static_body # Function call inside private expression -> entire body will be inlined into circuit. # Function must not have side-effects (only pure and view is allowed) and cannot have a nonstatic body (i.e. recursion) return self.gen.inline_function_call_into_circuit(ast)
def visitNumberLiteralExpr(self, ctx: SolidityParser.NumberLiteralExprContext): v = int(ctx.getText().replace('_', ''), 0) return NumberLiteralExpr(v, ctx.getText().startswith(('0x', '0X')))
def test_builtin_code(self): f = BuiltinFunction('+') c = FunctionCallExpr(f, [NumberLiteralExpr(0), NumberLiteralExpr(0)]) self.assertEqual(c.code(), '0 + 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
def create_external_wrapper_body(int_fct: ConstructorOrFunctionDefinition, ext_circuit: CircuitHelper, original_params: List[Parameter], requires_proof: bool) -> Block: """ Return Block with external wrapper function body. :param int_fct: corresponding internal function :param ext_circuit: [SIDE EFFECT] circuit helper of the external wrapper function :param original_params: list of transformed function parameters without additional parameters added due to transformation :return: body with wrapper code """ priv_args = [p for p in original_params if p.annotated_type.is_cipher()] args_backends = OrderedDict.fromkeys([p.annotated_type.type_name.crypto_params for p in priv_args]) stmts = [] for crypto_params in args_backends: assert crypto_params in int_fct.used_crypto_backends # If there are any private arguments with homomorphism 'hom', we need the public key for that crypto backend ext_circuit._require_public_key_for_label_at(None, Expression.me_expr(), crypto_params) for crypto_params in cfg.all_crypto_params(): if crypto_params.is_symmetric_cipher(): if (MeExpr(), crypto_params) in ext_circuit.requested_global_keys or crypto_params in args_backends: # Make sure msg.sender's key pair is available in the circuit stmts += ext_circuit.request_private_key(crypto_params) # Verify that out parameter has correct size stmts += [RequireStatement(IdentifierExpr(cfg.zk_out_name).dot('length').binop('==', NumberLiteralExpr(ext_circuit.out_size_trans)))] # IdentifierExpr for array var holding serialized public circuit inputs in_arr_var = IdentifierExpr(cfg.zk_in_name).as_type(Array(AnnotatedTypeName.uint_all())) # Request static public keys offset = 0 key_req_stmts = [] me_key_idx: Dict[CryptoParams, int] = {} if ext_circuit.requested_global_keys: # Ensure that me public key is stored starting at in[0] keys = [key for key in ext_circuit.requested_global_keys] tmp_keys = {} for crypto_params in int_fct.used_crypto_backends: tmp_key_var = Identifier(f'_tmp_key_{crypto_params.identifier_name}') key_req_stmts.append(tmp_key_var.decl_var(AnnotatedTypeName.key_type(crypto_params))) tmp_keys[crypto_params] = tmp_key_var for (key_owner, crypto_params) in keys: tmp_key_var = tmp_keys[crypto_params] idf, assignment = ext_circuit.request_public_key(crypto_params, key_owner, ext_circuit.get_glob_key_name(key_owner, crypto_params)) assignment.lhs = IdentifierExpr(tmp_key_var.clone()) key_req_stmts.append(assignment) # Remember me-keys for later use in symmetrically encrypted keys if key_owner == MeExpr(): assert crypto_params not in me_key_idx me_key_idx[crypto_params] = offset # Manually add to circuit inputs key_len = crypto_params.key_len key_req_stmts.append(in_arr_var.slice(offset, key_len).assign(IdentifierExpr(tmp_key_var.clone()).slice(0, key_len))) offset += key_len assert offset == ext_circuit.in_size # Check encrypted parameters param_stmts = [] for p in original_params: """ * of T_e rule 8 """ if p.annotated_type.is_cipher(): cipher_payload_len = p.annotated_type.type_name.crypto_params.cipher_payload_len assign_stmt = in_arr_var.slice(offset, cipher_payload_len).assign(IdentifierExpr(p.idf.clone()).slice(0, cipher_payload_len)) ext_circuit.ensure_parameter_encryption(assign_stmt, p) # Manually add to circuit inputs param_stmts.append(assign_stmt) offset += cipher_payload_len # Populate sender field of parameters encrypted with a symmetric cipher copy_stmts = [] for p in original_params: if p.annotated_type.is_cipher(): c = p.annotated_type.type_name assert isinstance(c, CipherText) if c.crypto_params.is_symmetric_cipher(): sender_key = in_arr_var.index(me_key_idx[c.crypto_params]) idf = IdentifierExpr(p.idf.clone()).as_type(p.annotated_type.clone()) cipher_payload_len = cfg.get_crypto_params(p.annotated_type.homomorphism).cipher_payload_len lit = ArrayLiteralExpr([idf.clone().index(i) for i in range(cipher_payload_len)] + [sender_key]) copy_stmts.append(VariableDeclarationStatement(VariableDeclaration([], p.annotated_type.clone(), p.idf.clone(), 'memory'), lit)) if copy_stmts: param_stmts += [Comment(), Comment('Copy from calldata to memory and set sender field')] + copy_stmts # Declare in array new_in_array_expr = NewExpr(AnnotatedTypeName(TypeName.dyn_uint_array()), [NumberLiteralExpr(ext_circuit.in_size_trans)]) in_var_decl = in_arr_var.idf.decl_var(TypeName.dyn_uint_array(), new_in_array_expr) stmts.append(in_var_decl) stmts.append(Comment()) stmts += Comment.comment_wrap_block('Request static public keys', key_req_stmts) stmts += Comment.comment_wrap_block('Backup private arguments for verification', param_stmts) # Call internal function args = [IdentifierExpr(param.idf.clone()) for param in original_params] internal_call = FunctionCallExpr(IdentifierExpr(int_fct.idf.clone()).override(target=int_fct), args) internal_call.sec_start_offset = ext_circuit.priv_in_size if int_fct.requires_verification: ext_circuit.call_function(internal_call) args += [in_arr_var.clone(), NumberLiteralExpr(ext_circuit.in_size), IdentifierExpr(cfg.zk_out_name), NumberLiteralExpr(ext_circuit.out_size)] if int_fct.return_parameters: stmts += Comment.comment_list("Declare return variables", [VariableDeclarationStatement(deep_copy(vd)) for vd in int_fct.return_var_decls]) in_call = TupleExpr([IdentifierExpr(vd.idf.clone()) for vd in int_fct.return_var_decls]).assign(internal_call) else: in_call = ExpressionStatement(internal_call) stmts.append(Comment("Call internal function")) stmts.append(in_call) stmts.append(Comment()) # Call verifier if requires_proof and not cfg.disable_verification: verifier = IdentifierExpr(cfg.get_contract_var_name(ext_circuit.verifier_contract_type.code())) verifier_args = [IdentifierExpr(cfg.proof_param_name), IdentifierExpr(cfg.zk_in_name), IdentifierExpr(cfg.zk_out_name)] verify = ExpressionStatement(verifier.call(cfg.verification_function_name, verifier_args)) stmts.append(StatementList([Comment('Verify zk proof of execution'), verify], excluded_from_simulation=True)) # Add return statement at the end if necessary if int_fct.return_parameters: stmts.append(ReturnStatement(TupleExpr([IdentifierExpr(vd.idf.clone()) for vd in int_fct.return_var_decls]))) return Block(stmts)
def create_internal_verification_wrapper(self, ast: ConstructorOrFunctionDefinition): """ Add the necessary additional parameters and boiler plate code for verification support to the given function. :param ast: [SIDE EFFECT] Internal function which requires verification """ circuit = self.circuits[ast] stmts = [] symmetric_cipher_used = any([backend.is_symmetric_cipher() for backend in ast.used_crypto_backends]) if symmetric_cipher_used and 'pure' in ast.modifiers: # Symmetric trafo requires msg.sender access -> change from pure to view ast.modifiers = ['view' if mod == 'pure' else mod for mod in ast.modifiers] # Add additional params ast.add_param(Array(AnnotatedTypeName.uint_all()), cfg.zk_in_name) ast.add_param(AnnotatedTypeName.uint_all(), f'{cfg.zk_in_name}_start_idx') ast.add_param(Array(AnnotatedTypeName.uint_all()), cfg.zk_out_name) ast.add_param(AnnotatedTypeName.uint_all(), f'{cfg.zk_out_name}_start_idx') # Verify that in/out parameters have correct size out_start_idx, in_start_idx = IdentifierExpr(f'{cfg.zk_out_name}_start_idx'), IdentifierExpr(f'{cfg.zk_in_name}_start_idx') out_var, in_var = IdentifierExpr(cfg.zk_out_name), IdentifierExpr(cfg.zk_in_name).as_type(Array(AnnotatedTypeName.uint_all())) stmts.append(RequireStatement(out_start_idx.binop('+', NumberLiteralExpr(circuit.out_size_trans)).binop('<=', out_var.dot('length')))) stmts.append(RequireStatement(in_start_idx.binop('+', NumberLiteralExpr(circuit.in_size_trans)).binop('<=', in_var.dot('length')))) # Declare zk_data struct var (if needed) if circuit.requires_zk_data_struct(): zk_struct_type = StructTypeName([Identifier(circuit.zk_data_struct_name)]) stmts += [Identifier(cfg.zk_data_var_name).decl_var(zk_struct_type), BlankLine()] # Declare return variable if necessary if ast.return_parameters: stmts += Comment.comment_list("Declare return variables", [VariableDeclarationStatement(vd) for vd in ast.return_var_decls]) # Find all me-keys in the in array me_key_idx: Dict[CryptoParams, int] = {} offset = 0 for (key_owner, crypto_params) in circuit.requested_global_keys: if key_owner == MeExpr(): assert crypto_params not in me_key_idx me_key_idx[crypto_params] = offset offset += crypto_params.key_len # Deserialize out array (if any) deserialize_stmts = [] offset = 0 for s in circuit.output_idfs: deserialize_stmts.append(s.deserialize(cfg.zk_out_name, out_start_idx, offset)) if isinstance(s.t, CipherText) and s.t.crypto_params.is_symmetric_cipher(): # Assign sender field to user-encrypted values if necessary # Assumption: s.t.crypto_params.key_len == 1 for all symmetric ciphers assert s.t.crypto_params in me_key_idx, "Symmetric cipher but did not request me key" key_idx = me_key_idx[s.t.crypto_params] sender_key = in_var.index(key_idx) cipher_payload_len = s.t.crypto_params.cipher_payload_len deserialize_stmts.append(s.get_loc_expr().index(cipher_payload_len).assign(sender_key)) offset += s.t.size_in_uints if deserialize_stmts: stmts.append(StatementList(Comment.comment_wrap_block("Deserialize output values", deserialize_stmts), excluded_from_simulation=True)) # Include original transformed function body stmts += ast.body.statements # Serialize in parameters to in array (if any) serialize_stmts = [] offset = 0 for s in circuit.input_idfs: serialize_stmts += [s.serialize(cfg.zk_in_name, in_start_idx, offset)] offset += s.t.size_in_uints if offset: stmts.append(Comment()) stmts += Comment.comment_wrap_block('Serialize input values', serialize_stmts) # Add return statement at the end if necessary # (was previously replaced by assignment to return_var by ZkayStatementTransformer) if circuit.has_return_var: stmts.append(ReturnStatement(TupleExpr([IdentifierExpr(vd.idf.clone()).override(target=vd) for vd in ast.return_var_decls]))) ast.body.statements[:] = stmts
def transform_contract(self, su: SourceUnit, c: ContractDefinition) -> ContractDefinition: """ Transform an entire zkay contract into a public solidity contract. This: * transforms state variables, function bodies and signatures * import verification contracts * adds zk_data structs for each function with verification \ (to store circuit I/O, to bypass solidity stack limit and allow for easy assignment of array variables), * creates external wrapper functions for all public functions which require verification * adds circuit IO serialization/deserialization code from/to zk_data struct to all functions which require verification. :param su: [SIDE EFFECTS] Source unit of which this contract is part of :param c: [SIDE EFFECTS] The contract to transform :return: The contract itself """ all_fcts = c.constructor_definitions + c.function_definitions # Get list of static owner labels for this contract global_owners = [Expression.me_expr()] for var in c.state_variable_declarations: if var.annotated_type.is_address() and (var.is_final or var.is_constant): global_owners.append(var.idf) # Backup untransformed function bodies for fct in all_fcts: fct.original_body = deep_copy(fct.body, with_types=True, with_analysis=True) # Transform types of normal state variables c.state_variable_declarations = self.var_decl_trafo.visit_list(c.state_variable_declarations) # Split into functions which require verification and those which don't need a circuit helper req_ext_fcts = {} new_fcts, new_constr = [], [] for fct in all_fcts: assert isinstance(fct, ConstructorOrFunctionDefinition) if fct.requires_verification or fct.requires_verification_when_external: self.circuits[fct] = self.create_circuit_helper(fct, global_owners) if fct.requires_verification_when_external: req_ext_fcts[fct] = fct.parameters[:] elif fct.is_constructor: new_constr.append(fct) else: new_fcts.append(fct) # Add constant state variables for external contracts and field prime field_prime_decl = StateVariableDeclaration(AnnotatedTypeName.uint_all(), ['public', 'constant'], Identifier(cfg.field_prime_var_name), NumberLiteralExpr(bn128_scalar_field)) contract_var_decls = self.include_verification_contracts(su, c) c.state_variable_declarations = [field_prime_decl, Comment()]\ + Comment.comment_list('Helper Contracts', contract_var_decls)\ + [Comment('User state variables')]\ + c.state_variable_declarations # Transform signatures for f in all_fcts: f.parameters = self.var_decl_trafo.visit_list(f.parameters) for f in c.function_definitions: f.return_parameters = self.var_decl_trafo.visit_list(f.return_parameters) f.return_var_decls = self.var_decl_trafo.visit_list(f.return_var_decls) # Transform bodies for fct in all_fcts: gen = self.circuits.get(fct, None) fct.body = ZkayStatementTransformer(gen).visit(fct.body) # Transform (internal) functions which require verification (add the necessary additional parameters and boilerplate code) fcts_with_verification = [fct for fct in all_fcts if fct.requires_verification] compute_transitive_circuit_io_sizes(fcts_with_verification, self.circuits) transform_internal_calls(fcts_with_verification, self.circuits) for f in fcts_with_verification: circuit = self.circuits[f] assert circuit.requires_verification() if circuit.requires_zk_data_struct(): # Add zk data struct for f to contract zk_data_struct = StructDefinition(Identifier(circuit.zk_data_struct_name), [ VariableDeclaration([], AnnotatedTypeName(idf.t), idf.clone(), '') for idf in circuit.output_idfs + circuit.input_idfs ]) c.struct_definitions.append(zk_data_struct) self.create_internal_verification_wrapper(f) # Create external wrapper functions where necessary for f, params in req_ext_fcts.items(): ext_f, int_f = self.split_into_external_and_internal_fct(f, params, global_owners) if ext_f.is_function: new_fcts.append(ext_f) else: new_constr.append(ext_f) new_fcts.append(int_f) c.constructor_definitions = new_constr c.function_definitions = new_fcts return c
def create_external_wrapper_body(int_fct: ConstructorOrFunctionDefinition, ext_circuit: CircuitHelper, original_params: List[Parameter], requires_proof: bool) -> Block: """ Return Block with external wrapper function body. :param int_fct: corresponding internal function :param ext_circuit: [SIDE EFFECT] circuit helper of the external wrapper function :param original_params: list of transformed function parameters without additional parameters added due to transformation :return: body with wrapper code """ has_priv_args = any( [p.annotated_type.is_cipher() for p in original_params]) stmts = [] if has_priv_args: ext_circuit._require_public_key_for_label_at( None, Expression.me_expr()) if cfg.is_symmetric_cipher(): # Make sure msg.sender's key pair is available in the circuit assert any(isinstance(k, MeExpr) for k in ext_circuit.requested_global_keys) \ or has_priv_args, "requires verification => both sender keys required" stmts += ext_circuit.request_private_key() # Verify that out parameter has correct size stmts += [ RequireStatement( IdentifierExpr(cfg.zk_out_name).dot('length').binop( '==', NumberLiteralExpr(ext_circuit.out_size_trans))) ] # IdentifierExpr for array var holding serialized public circuit inputs in_arr_var = IdentifierExpr(cfg.zk_in_name).as_type( Array(AnnotatedTypeName.uint_all())) # Find index of me's public key in requested_global_keys glob_me_key_index = -1 for idx, e in enumerate(ext_circuit.requested_global_keys): if isinstance(e, MeExpr): glob_me_key_index = idx break # Request static public keys offset = 0 key_req_stmts = [] if ext_circuit.requested_global_keys: # Ensure that me public key is stored starting at in[0] keys = [key for key in ext_circuit.requested_global_keys] if glob_me_key_index != -1: (keys[0], keys[glob_me_key_index]) = (keys[glob_me_key_index], keys[0]) tmp_key_var = Identifier('_tmp_key') key_req_stmts.append( tmp_key_var.decl_var(AnnotatedTypeName.key_type())) for key_owner in keys: idf, assignment = ext_circuit.request_public_key( key_owner, ext_circuit.get_glob_key_name(key_owner)) assignment.lhs = IdentifierExpr(tmp_key_var.clone()) key_req_stmts.append(assignment) # Manually add to circuit inputs key_req_stmts.append( in_arr_var.slice(offset, cfg.key_len).assign( IdentifierExpr(tmp_key_var.clone()).slice( 0, cfg.key_len))) offset += cfg.key_len assert offset == ext_circuit.in_size # Check encrypted parameters param_stmts = [] for p in original_params: """ * of T_e rule 8 """ if p.annotated_type.is_cipher(): assign_stmt = in_arr_var.slice( offset, cfg.cipher_payload_len).assign( IdentifierExpr(p.idf.clone()).slice( 0, cfg.cipher_payload_len)) ext_circuit.ensure_parameter_encryption(assign_stmt, p) # Manually add to circuit inputs param_stmts.append(assign_stmt) offset += cfg.cipher_payload_len if cfg.is_symmetric_cipher(): # Populate sender field of encrypted parameters copy_stmts = [] for p in original_params: if p.annotated_type.is_cipher(): sender_key = in_arr_var.index(0) idf = IdentifierExpr(p.idf.clone()).as_type( p.annotated_type.clone()) lit = ArrayLiteralExpr([ idf.clone().index(i) for i in range(cfg.cipher_payload_len) ] + [sender_key]) copy_stmts.append( VariableDeclarationStatement( VariableDeclaration([], p.annotated_type.clone(), p.idf.clone(), 'memory'), lit)) if copy_stmts: param_stmts += [ Comment(), Comment( 'Copy from calldata to memory and set sender field') ] + copy_stmts assert glob_me_key_index != -1, "Symmetric cipher but did not request me key" # Declare in array new_in_array_expr = NewExpr( AnnotatedTypeName(TypeName.dyn_uint_array()), [NumberLiteralExpr(ext_circuit.in_size_trans)]) in_var_decl = in_arr_var.idf.decl_var(TypeName.dyn_uint_array(), new_in_array_expr) stmts.append(in_var_decl) stmts.append(Comment()) stmts += Comment.comment_wrap_block('Request static public keys', key_req_stmts) stmts += Comment.comment_wrap_block( 'Backup private arguments for verification', param_stmts) # Call internal function args = [IdentifierExpr(param.idf.clone()) for param in original_params] internal_call = FunctionCallExpr( IdentifierExpr(int_fct.idf.clone()).override(target=int_fct), args) internal_call.sec_start_offset = ext_circuit.priv_in_size if int_fct.requires_verification: ext_circuit.call_function(internal_call) args += [ in_arr_var.clone(), NumberLiteralExpr(ext_circuit.in_size), IdentifierExpr(cfg.zk_out_name), NumberLiteralExpr(ext_circuit.out_size) ] if int_fct.return_parameters: stmts += Comment.comment_list("Declare return variables", [ VariableDeclarationStatement(deep_copy(vd)) for vd in int_fct.return_var_decls ]) in_call = TupleExpr([ IdentifierExpr(vd.idf.clone()) for vd in int_fct.return_var_decls ]).assign(internal_call) else: in_call = ExpressionStatement(internal_call) stmts.append(Comment("Call internal function")) stmts.append(in_call) stmts.append(Comment()) # Call verifier if requires_proof: verifier = IdentifierExpr( cfg.get_contract_var_name( ext_circuit.verifier_contract_type.code())) verifier_args = [ IdentifierExpr(cfg.proof_param_name), IdentifierExpr(cfg.zk_in_name), IdentifierExpr(cfg.zk_out_name) ] verify = ExpressionStatement( verifier.call(cfg.verification_function_name, verifier_args)) stmts.append( StatementList( [Comment('Verify zk proof of execution'), verify], excluded_from_simulation=True)) # Add return statement at the end if necessary if int_fct.return_parameters: stmts.append( ReturnStatement( TupleExpr([ IdentifierExpr(vd.idf.clone()) for vd in int_fct.return_var_decls ]))) return Block(stmts)