You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: vm.rs
    path of file: ./repos/darkfi/src/zk
    
    the code of the file until where you have to start completion: /* This file is part of DarkFi (https://dark.fi)
 *
 * Copyright (C) 2020-2024 Dyne.org foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Pu
    
    fn params(&self) -> Self::Params {
        // Gather all opcodes used in the circuit.
        let mut opcodes = HashSet::new();
        for (opcode, _) in &self.opcodes {
            opcodes.insert(opcode);
        }

        // Conditions on which we enable the ECC chip
        let init_ecc = !self.constants.is_empty() ||
            opcodes.contains(&Opcode::EcAdd) ||
            opcodes.contains(&Opcode::EcMul) ||
            opcodes.contains(&Opcode::EcMulBase) ||
            opcodes.contains(&Opcode::EcMulShort) ||
            opcodes.contains(&Opcode::EcMulVarBase) ||
            opcodes.contains(&Opcode::EcGetX) ||
            opcodes.contains(&Opcode::EcGetY) ||
            opcodes.contains(&Opcode::ConstrainEqualPoint) ||
            self.witnesses.iter().any(|x| {
                matches!(x, Witness::EcPoint(_)) ||
                    matches!(x, Witness::EcNiPoint(_)) ||
                    matches!(x, Witness::EcFixedPoint(_)) ||
                    matches!(x, Witness::Scalar(_))
            });

        // Conditions on which we enable the Poseidon hash chip
        let init_poseidon = opcodes.contains(&Opcode::PoseidonHash);

        // Conditions on which we enable the Sinsemilla and Merkle chips
        let init_sinsemilla = opcodes.contains(&Opcode::MerkleRoot);

        // Conditions on which we enable the base field Arithmetic chip
        let init_arithmetic = opcodes.contains(&Opcode::BaseAdd) ||
            opcodes.contains(&Opcode::BaseSub) ||
            opcodes.contains(&Opcode::BaseMul);

        // Conditions on which we enable the native range check chips
        // TODO: Separate 253 and 64.
        let init_nativerange = opcodes.contains(&Opcode::RangeCheck) ||
            opcodes.contains(&Opcode::LessThanLoose) ||
            opcodes.contains(&Opcode::LessThanStrict);

        // Conditions on which we enable the less than comparison chip
        let init_lessthan =
            opcodes.contains(&Opcode::LessThanLoose) || opcodes.contains(&Opcode::LessThanStrict);

        // Conditions on which we enable the boolean check chip
        let init_boolcheck = opcodes.contains(&Opcode::BoolCheck);

        // Conditions on which we enable the conditional selection chip
        let init_condselect = opcodes.contains(&Opcode::CondSelect);

        // Conditions on which we enable the zero cond selection chip
        let init_zerocond = opcodes.contains(&Opcode::ZeroCondSelect);

        ZkParams {
            init_ecc,
            init_poseidon,
            init_sinsemilla,
            init_arithmetic,
            init_nativerange,
            init_lessthan,
            init_boolcheck,
            init_condselect,
            init_zerocond,
        }
    }