Writing a blake2s prover

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(&params.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, &params, 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.

1 Like

Many ECC engineers are still in Croatia, or have only just got back. We can continue discussion on https://github.com/zcash/librustzcash/issues/87