1 unstable release
0.1.0 | Oct 2, 2023 |
---|
#2345 in Cryptography
97KB
2K
SLoC
Monolith Plonky2
This crate provides an implementation of the Monolith hash function that can be employed in the Plonky2 proving system. 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:
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<dyn Error>> {
let config = CircuitConfig::standard_recursion_config();
let mut builder = CircuitBuilder::<F, D>::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::<MonolithGoldilocksConfig>();
let mut pw = PartialWitness::<F>::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:
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::<F,D>::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<dyn Error>> {
let config = generate_config_for_monolith();
let mut builder = CircuitBuilder::<F, D>::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::<MonolithHash>(res_targets_array.to_vec()).elements;
}
builder.register_public_inputs(&res_targets_array);
let data = builder.build::<MonolithGoldilocksConfig>();
let mut pw = PartialWitness::<F>::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)?)
}
Dependencies
~7.5MB
~150K SLoC