def visitVariableDeclaration(self, ast: VariableDeclaration): ast.modified_values[InstanceTarget(ast)] = None
# BUILTIN SPECIAL TYPE DEFINITIONS from zkay.zkay_ast.ast import AnnotatedTypeName, FunctionTypeName, Parameter, Identifier, StructDefinition, \ VariableDeclaration, TypeName, StateVariableDeclaration, UserDefinedTypeName, StructTypeName, Block, ConstructorOrFunctionDefinition from zkay.zkay_ast.pointers.parent_setter import set_parents array_length_member = VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('length')) class GlobalDefs: # gasleft: FunctionDefinition = FunctionDefinition( # idf=Identifier('gasleft'), # parameters=[], # modifiers=[], # return_parameters=[Parameter([], annotated_type=AnnotatedTypeName.uint_all(), idf=Identifier(''))], # body=Block([]) # ) # gasleft.idf.parent = gasleft address_struct: StructDefinition = StructDefinition( Identifier('<address>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('balance')) ]) set_parents(address_struct) address_payable_struct: StructDefinition = StructDefinition( Identifier('<address_payable>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('balance')), ConstructorOrFunctionDefinition(
class GlobalDefs: # gasleft: FunctionDefinition = FunctionDefinition( # idf=Identifier('gasleft'), # parameters=[], # modifiers=[], # return_parameters=[Parameter([], annotated_type=AnnotatedTypeName.uint_all(), idf=Identifier(''))], # body=Block([]) # ) # gasleft.idf.parent = gasleft address_struct: StructDefinition = StructDefinition( Identifier('<address>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('balance')) ]) set_parents(address_struct) address_payable_struct: StructDefinition = StructDefinition( Identifier('<address_payable>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('balance')), ConstructorOrFunctionDefinition( Identifier('send'), [Parameter([], AnnotatedTypeName.uint_all(), Identifier(''))], ['public'], [Parameter([], AnnotatedTypeName.bool_all(), Identifier(''))], Block([])), ConstructorOrFunctionDefinition( Identifier('transfer'), [Parameter([], AnnotatedTypeName.uint_all(), Identifier(''))], ['public'], [], Block([])), ]) address_payable_struct.members[1].can_be_private = False address_payable_struct.members[2].can_be_private = False set_parents(address_payable_struct) msg_struct: StructDefinition = StructDefinition(Identifier('<msg>'), [ VariableDeclaration([], AnnotatedTypeName(TypeName.address_payable_type()), Identifier('sender')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('value')), ]) set_parents(msg_struct) block_struct: StructDefinition = StructDefinition(Identifier('<block>'), [ VariableDeclaration([], AnnotatedTypeName(TypeName.address_payable_type()), Identifier('coinbase')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('difficulty')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('gaslimit')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('number')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('timestamp')), ]) set_parents(block_struct) tx_struct: StructDefinition = StructDefinition(Identifier('<tx>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('gasprice')), VariableDeclaration([], AnnotatedTypeName(TypeName.address_payable_type()), Identifier('origin')), ]) set_parents(tx_struct)
def visitVariableDeclaration(self, ast: VariableDeclaration): if ast.annotated_type.is_private(): ast.storage_location = 'memory' return self.visit_children(ast)
def handle_function_body(self, ast: ConstructorOrFunctionDefinition): """ Return offchain simulation python code for the body of function ast. In addition to what the original code does, the generated python code also: * checks that internal functions are not called externally * processes arguments (encryption, address wrapping for external calls), * introduces msg, block and tx objects as local variables (populated with current blockchain state) * serializes the public circuit outputs and the private circuit inputs, which are obtained during \ simulation into int lists so that they can be passed to the proof generation * generates the NIZK proof (if needed) * calls/issues transaction with transformed arguments ((encrypted) original args, out array, proof) (or deploys the contract in case of the constructor) """ preamble_str = '' if ast.is_external: preamble_str += f'assert {IS_EXTERNAL_CALL}\n' preamble_str += f'msg, block, tx = {api("get_special_variables")}()\n' \ f'now = block.timestamp\n' circuit = self.current_circ if circuit and circuit.sec_idfs: priv_struct = StructDefinition(None, [ VariableDeclaration([], AnnotatedTypeName(sec_idf.t), sec_idf) for sec_idf in circuit.sec_idfs ]) preamble_str += f'\n{PRIV_VALUES_NAME}: Dict[str, Any] = {self.get_default_value(StructTypeName([], priv_struct))}\n' all_params = ', '.join( [f'{self.visit(param.idf)}' for param in self.current_params]) if ast.can_be_external: # Wrap address strings in AddressValue object for external calls address_params = [ self.visit(param.idf) for param in self.current_params if param.annotated_type.zkay_type.is_address() ] if address_params: assign_addr_str = f"{', '.join(address_params)} = {', '.join([f'AddressValue({p})' for p in address_params])}" preamble_str += f'\n{self.do_if_external(ast, [assign_addr_str])}\n' if ast.can_be_external and circuit: # Encrypt parameters and add private circuit inputs (plain + randomness) enc_param_str = '' for arg in self.current_params: if arg.annotated_type.is_cipher(): assert isinstance(arg.annotated_type.type_name, CipherText) cipher: CipherText = arg.annotated_type.type_name pname = self.visit(arg.idf) plain_val = pname plain_t = cipher.plain_type.type_name crypto_params = cipher.crypto_params crypto_str = f'crypto_backend="{crypto_params.crypto_name}"' if plain_t.is_signed_numeric and crypto_params.enc_signed_as_unsigned: plain_val = self.handle_cast( pname, UintTypeName(f'uint{plain_t.elem_bitwidth}')) enc_param_str += f'{self.get_priv_value(arg.idf.name)} = {plain_val}\n' if crypto_params.is_symmetric_cipher(): my_pk = f'{api("get_my_pk")}("{crypto_params.crypto_name}")[0]' enc_expr = f'{api("enc")}({self.get_priv_value(arg.idf.name)}, {crypto_str})' enc_param_str += f'{pname} = CipherValue({enc_expr}[0][:-1] + ({my_pk}, ), {crypto_str})\n' else: enc_expr = f'{api("enc")}({self.get_priv_value(arg.idf.name)}, {crypto_str})' enc_param_str += f'{pname}, {self.get_priv_value(f"{arg.idf.name}_R")} = {enc_expr}\n' enc_param_comment_str = '\n# Encrypt parameters' if enc_param_str else '' enc_param_str = enc_param_str[:-1] if enc_param_str else '' actual_params_assign_str = f"actual_params = [{all_params}]" out_var_decl_str = f'{cfg.zk_out_name}: List[int] = [0 for _ in range({circuit.out_size_trans})]' out_var_decl_str += f'\nactual_params.append({cfg.zk_out_name})' pre_body_code = self.do_if_external(ast, [ enc_param_comment_str, enc_param_str, actual_params_assign_str, out_var_decl_str ]) elif ast.can_be_external: pre_body_code = f'actual_params = [{all_params}]' else: pre_body_code = '' # Simulate public contract to compute in_values (state variable values are pulled from blockchain if necessary) # (out values are also computed when encountered, by locally evaluating and encrypting # the corresponding private expressions) body_str = self.visit(ast.body).strip() serialize_str = '' if circuit is not None: if circuit.output_idfs: out_elemwidths = ', '.join([ str(out.t.elem_bitwidth) if out.t.is_primitive_type() else '0' for out in circuit.output_idfs ]) serialize_str += f'\n{cfg.zk_out_name}[{cfg.zk_out_name}_start_idx:{cfg.zk_out_name}_start_idx + {circuit.out_size}] = ' \ f'{api("serialize_circuit_outputs")}(zk__data, [{out_elemwidths}])' if circuit.sec_idfs: sec_elemwidths = ', '.join([ str(sec.t.elem_bitwidth) if sec.t.is_primitive_type() else '0' for sec in circuit.sec_idfs ]) serialize_str += f'\n{api("serialize_private_inputs")}({PRIV_VALUES_NAME}, [{sec_elemwidths}])' if serialize_str: serialize_str = f'\n# Serialize circuit outputs and/or secret circuit inputs\n' + serialize_str.lstrip( ) body_code = '\n'.join( dedent(s) for s in [ f'\n## BEGIN Simulate body', body_str, '## END Simulate body', serialize_str, ] if s) + '\n' # Add proof to actual argument list (when required) generate_proof_str = '' fname = f"'{ast.name}'" if ast.can_be_external and circuit and ast.has_side_effects: generate_proof_str += '\n'.join([ '\n#Generate proof', f"proof = {api('gen_proof')}({fname}, {cfg.zk_in_name}, {cfg.zk_out_name})", 'actual_params.append(proof)' ]) should_encrypt = ", ".join([ str(p.annotated_type.is_cipher()) for p in self.current_f.parameters ]) if ast.is_constructor: invoke_transact_str = f''' # Deploy contract {api("deploy")}(actual_params, [{should_encrypt}]{", wei_amount=wei_amount" if ast.is_payable else ""}) ''' elif ast.has_side_effects: invoke_transact_str = f''' # Invoke public transaction return {api("transact")}({fname}, actual_params, [{should_encrypt}]{", wei_amount=wei_amount" if ast.is_payable else ""}) ''' elif ast.return_parameters: constructors = [] for retparam in ast.return_parameters: t = retparam.annotated_type.type_name if isinstance(t, CipherText): constr = f'(True, "{t.crypto_params.crypto_name}", {self._get_type_constr(t.plain_type.type_name)})' else: constr = f'(False, None, {self._get_type_constr(t)})' constructors.append(constr) constructors = f"[{', '.join(constructors)}]" invoke_transact_str = f''' # Call pure/view function and return value return {api('call')}({fname}, actual_params, {constructors}) ''' else: invoke_transact_str = '' post_body_code = self.do_if_external(ast, [ generate_proof_str, invoke_transact_str ], [ f'return {", ".join([f"{cfg.return_var_name}_{idx}" for idx in range(len(ast.return_parameters))])}' if ast.is_function and ast.requires_verification and ast.return_parameters else None ]) code = '\n\n'.join(s.strip() for s in [ f'assert not {IS_EXTERNAL_CALL}' if not ast.can_be_external else None, dedent(preamble_str), pre_body_code, body_code, post_body_code ] if s) func_ctx_params = [] if circuit: func_ctx_params.append(str(circuit.priv_in_size_trans)) if ast.is_payable: func_ctx_params.append('wei_amount=wei_amount') if ast.can_be_external: func_ctx_params.append(f'name={fname}') code = 'with time_measure("transaction_full", skip=not zk__is_ext):\n' + indent( code) code = f'with self._function_ctx({", ".join(func_ctx_params)}) as {IS_EXTERNAL_CALL}:\n' + indent( code) return code
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 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)
def visitVariableDeclaration(self, ast: VariableDeclaration): ast.names = {ast.idf.name: ast.idf}
def visitIndexExpr(self, ast: IndexExpr): assert isinstance(ast.arr, LocationExpr), "Function call return value indexing not yet supported" source_t = ast.arr.target.annotated_type.type_name ast.target = VariableDeclaration([], source_t.value_type, Identifier(''))