# Monolith Plonky2 This crate provides an implementation of the [Monolith hash function](https://eprint.iacr.org/2023/1025.pdf) that can be employed in the [Plonky2 proving system](https://github.com/mir-protocol/plonky2). Monolith hash function is a new zk-friendly hash function which is much faster than state-of-the-art zk-friendly hash functions, exhibiting performance similar to the Keccak hash function. In particular, according to our initial benchmarks, Monolith is from 2 to 3 times faster than Poseidon, the current hash function employed in the Plonky2 proving system. This crate can be employed to: - Generate Plonky2 proofs employing Monolith hash function - Write Plonky2 circuits computing Monolith hashes, which is also useful to recursively verify Plonky2 proofs generated with Monolith. To this extent, this crate provides a Plonky2 gate for the Monolith permutation. The crate also provides benchmarks that compare the Monolith implementation and the Monolith gate with the corresponding Poseidon components currently employed in Plonky2. ## Usage Generate a proof employing Monolith hash function: ```rust use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::iop::witness::PartialWitness; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::field::types::Sample; use plonky2::iop::witness::WitnessWrite; use plonky2_monolith::monolith_hash::monolith_goldilocks::MonolithGoldilocksConfig; use std::error::Error; const D: usize = 2; type F = GoldilocksField; fn main() -> Result<(), Box> { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); let init_t = builder.add_virtual_public_input(); let mut res_t = builder.add_virtual_target(); builder.connect(init_t, res_t); for _ in 0..100 { res_t = builder.mul(res_t, init_t); } builder.register_public_input(res_t); let data = builder.build::(); let mut pw = PartialWitness::::new(); let input = F::rand(); pw.set_target(init_t, input); let proof = data.prove(pw)?; Ok(data.verify(proof)?) } ``` Build a circuit employing Monolith gate: ```rust use std::cmp; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::iop::witness::PartialWitness; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::field::types::Sample; use plonky2::iop::witness::WitnessWrite; use plonky2::gates::gate::Gate; use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; use plonky2_monolith::monolith_hash::monolith_goldilocks::MonolithGoldilocksConfig; use plonky2_monolith::gates::monolith::MonolithGate; use plonky2_monolith::monolith_hash::MonolithHash; use std::error::Error; const D: usize = 2; type F = GoldilocksField; fn generate_config_for_monolith() -> CircuitConfig { let needed_wires = cmp::max(MonolithGate::::new().num_wires(), CircuitConfig::standard_recursion_config().num_wires); CircuitConfig { num_wires: needed_wires, num_routed_wires: needed_wires, ..CircuitConfig::standard_recursion_config() } } fn main() -> Result<(), Box> { let config = generate_config_for_monolith(); let mut builder = CircuitBuilder::::new(config); let inp_targets_array = builder.add_virtual_target_arr::<{NUM_HASH_OUT_ELTS}>(); let mut res_targets_array = inp_targets_array.clone(); for _ in 0..100 { res_targets_array = builder.hash_or_noop::(res_targets_array.to_vec()).elements; } builder.register_public_inputs(&res_targets_array); let data = builder.build::(); let mut pw = PartialWitness::::new(); inp_targets_array.into_iter().for_each(|t| { let input = F::rand(); pw.set_target(t, input); }); let proof = data.prove(pw)?; Ok(data.verify(proof)?) } ```