I posted this question on the librustzcash repo but have not gotten a response yet.
I’m hoping to get a response here.
I’m trying to write a test similar to the one written in mimc.rs
which does the following steps for the mimc hash function: generate parameters, create proof and then verify it. I want to do this for the blake2s hash function using the blake2s circuit already implemented in the sapling-crypto crate. The problem I am having is that verification is failing and I don’t know what I’m doing wrong. Here are the major components of the code
/// This is our demo circuit for proving knowledge of the
/// preimage of a Blake2s hash invocation.
struct Blake2sDemo<E: Engine> {
preimage: Vec<Boolean>,
phantom: PhantomData<E>
}
impl<E: Engine> Circuit<E> for Blake2sDemo<E> {
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>
{
// Compute blake2s circuit
let image = blake2s::blake2s(
cs.namespace(|| "computation of image"),
&self.preimage,
CRH_IVK_PERSONALIZATION
)?;
// makes the image a public input to the circuit
multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &image);
Ok(())
}
}
fn test_blake2s() {
let rng = &mut thread_rng();
// Create parameters for our circuit
let mut rng2 = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let input_len = 8;
let data: Vec<u8> = (0..input_len).map(|_| rng2.gen()).collect();
let params = {
let c = Blake2sDemo {
preimage: convert_to_boolean_vec(&data),
phantom: PhantomData
};
generate_random_parameters::<Bls12, _, _>(c, rng).unwrap()
};
// Prepare the verification key (for proof verification)
let pvk = prepare_verifying_key(¶ms.vk);
const SAMPLES: u32 = 1;
let mut proof_vec = vec![];
for _ in 0..SAMPLES {
// Generate a random preimage and compute its hash
let mut rng2 = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let input_len = 8;
let mut h = Blake2s::with_params(32, &[], &[], CRH_IVK_PERSONALIZATION);
let data: Vec<u8> = (0..input_len).map(|_| rng2.gen()).collect();
h.update(&data);
let hash_result = h.finalize();
let preimage = data;
let image = hash_result.as_ref().to_vec();
proof_vec.truncate(0);
// Create an instance of our circuit (with the witness)
{
let c = Blake2sDemo {
preimage: convert_to_boolean_vec(&preimage),
phantom: PhantomData
};
// Create a groth16 proof with our parameters.
let proof = create_random_proof(c, ¶ms, rng).unwrap();
proof.write(&mut proof_vec).unwrap();
}
total_proving += start.elapsed();
let start = Instant::now();
let proof = Proof::read(&proof_vec[..]).unwrap();
let mut public_input = [Fr::zero(); 2];
// Add the blake2s hash output as public input to circuit through multiscalar packing
{
let image = multipack::bytes_to_bits_le(&image);
println!("num bits of black256: {}", image.len());
let image = multipack::compute_multipacking::<Bls12>(&image);
assert_eq!(image.len(), 2);
public_input[0] = image[0];
public_input[1] = image[1];
println!("pub input 0: {:?}", public_input[0]);
println!("pub input 1: {:?}", public_input[1]);
}
// Check the proof: THIS FAILS
assert!(verify_proof(
&pvk,
&proof,
&public_input
).unwrap());
}
}
I’ve spent many days debugging ensuring things like I’m passing the correct preimage to the circuit and hash function. What am I missing? Is parameter generation supposed to be done differently?
My overall goal is to strip out components of the full sapling circuit to build a smaller circuit and this test was my first step towards that. Any help would be appreciated.