pub fn verify(
        proof: &[u8],
        sp1_public_inputs: &[u8],
        sp1_vkey_hash: &str,
        groth16_vk: &[u8],
    ) -> Result<(), Groth16Error> {
        if proof.len() < VK_HASH_PREFIX_LENGTH {
            return Err(Groth16Error::GeneralError(Error::InvalidData));
        }

        // Hash the vk and get the first 4 bytes.
        let groth16_vk_hash: [u8; 4] = Sha256::digest(groth16_vk)[..VK_HASH_PREFIX_LENGTH]
            .try_into()
            .map_err(|_| Groth16Error::GeneralError(Error::InvalidData))?;

        // Check to make sure that this proof was generated by the groth16 proving key corresponding
        // to the given groth16_vk.
        //
        // SP1 prepends the raw Groth16 proof with the first 4 bytes of the groth16 vkey to
        // facilitate this check.
        if groth16_vk_hash != proof[..VK_HASH_PREFIX_LENGTH] {
            return Err(Groth16Error::Groth16VkeyHashMismatch);
        }

        let sp1_vkey_hash = decode_sp1_vkey_hash(sp1_vkey_hash)?;

        // It is computationally infeasible to find two distinct inputs, one processed with
        // SHA256 and the other with Blake3, that yield the same hash value.
        if Self::verify_gnark_proof(
            &proof[VK_HASH_PREFIX_LENGTH..],
            &[sp1_vkey_hash, hash_public_inputs(sp1_public_inputs)],
            groth16_vk,
        )
        .is_ok()
        {
            return Ok(())
        }

        Self::verify_gnark_proof(
            &proof[VK_HASH_PREFIX_LENGTH..],
            &[sp1_vkey_hash, hash_public_inputs_with_fn(sp1_public_inputs, blake3_hash)],
            groth16_vk,
        )
    }
Verifies an SP1 Groth16 proof, as generated by the SP1 SDK.

# Arguments

* `proof` - The proof bytes.
* `public_inputs` - The SP1 public inputs.
* `sp1_vkey_hash` - The SP1 vkey hash. This is generated in the following manner:

```ignore
use sp1_sdk::ProverClient;
let client = ProverClient::new();
let (pk, vk) = client.setup(ELF);
let sp1_vkey_hash = vk.bytes32();
```
* `groth16_vk` - The Groth16 verifying key bytes. Usually this will be the
[`static@crate::GROTH16_VK_BYTES`] constant, which is the Groth16 verifying key for the
current SP1 version.

# Returns

A success [`Result`] if verification succeeds, or a [`Groth16Error`] if verification fails.
crates/verifier/src/groth16/mod.rs