sp1-solana 0.1.0

Verifier for SP1 Groth16 proofs on Solana
Documentation
//! # Verifier
//!
//! This crate contains utilities for verifying SP1 Groth16 proofs on Solana.
//!
//! # Example
//! ```no_run
//! use sp1_sdk::proof::SP1ProofWithPublicValues;
//! use sp1_solana::{verify_proof, GROTH16_VK_2_0_0_BYTES};
//!
//! // Load the sp1_proof_with_public_values from a file.
//! let sp1_proof_with_public_values_file = "../proofs/fibonacci_proof.bin";
//! let sp1_proof_with_public_values =
//!     SP1ProofWithPublicValues::load(&sp1_proof_with_public_values_file).unwrap();
//!
//! // Fetch the proof and public inputs from the SP1ProofWithPublicValues.
//! let proof_bytes = sp1_proof_with_public_values.bytes();
//! let sp1_public_inputs = sp1_proof_with_public_values.public_values.to_vec();
//!
//! // Typically, the vkey hash is computed from `vk.bytes32()` on the SP1 program's vkey.
//! let vkey_hash = "0x0083e8e370d7f0d1c463337f76c9a60b62ad7cc54c89329107c92c1e62097872";
//!
//! verify_proof(&proof_bytes, &sp1_public_inputs, &vkey_hash, &GROTH16_VK_2_0_0_BYTES).unwrap();
//! ```

use groth16_solana::groth16::Groth16Verifyingkey;
use sha2::{Digest, Sha256};

#[cfg(test)]
mod test;

mod utils;
use utils::*;

/// Groth16 verification keys for different SP1 versions.
pub const GROTH16_VK_5_0_0_BYTES: &[u8] = include_bytes!("../vk/v5.0.0/groth16_vk.bin");
pub const GROTH16_VK_4_0_0_RC3_BYTES: &[u8] = include_bytes!("../vk/v4.0.0-rc.3/groth16_vk.bin");
pub const GROTH16_VK_3_0_0_BYTES: &[u8] = include_bytes!("../vk/v3.0.0/groth16_vk.bin");
pub const GROTH16_VK_3_0_0_RC4_BYTES: &[u8] = include_bytes!("../vk/v3.0.0rc4/groth16_vk.bin");
pub const GROTH16_VK_2_0_0_BYTES: &[u8] = include_bytes!("../vk/v2.0.0/groth16_vk.bin");

/// Verifies a proof using raw bytes, without any checks.
///
/// The public inputs are the vkey hash and the commited values digest, concatenated.
/// The proof is a decompressed G1 element, followed by a decompressed G2 element, followed by a
/// decompressed G1 element.
pub fn verify_proof_raw(proof: &[u8], public_inputs: &[u8], vk: &[u8]) -> Result<(), Error> {
    let proof = load_proof_from_bytes(proof)?;
    let vk = load_groth16_verifying_key_from_bytes(vk)?;
    let public_inputs = load_public_inputs_from_bytes(public_inputs)?;

    let vk = Groth16Verifyingkey {
        nr_pubinputs: vk.nr_pubinputs as usize,
        vk_alpha_g1: vk.vk_alpha_g1,
        vk_beta_g2: vk.vk_beta_g2,
        vk_gamme_g2: vk.vk_gamma_g2,
        vk_delta_g2: vk.vk_delta_g2,
        vk_ic: vk.vk_ic.as_slice(),
    };

    let mut verifier = groth16_solana::groth16::Groth16Verifier::new(
        &proof.pi_a,
        &proof.pi_b,
        &proof.pi_c,
        &public_inputs.inputs,
        &vk,
    )
    .map_err(|_| Error::VerificationError)?;

    verifier.verify().map_err(|_| Error::VerificationError)
}

/// Verifies a proof generated by [`SP1ProofWithPublicValues`].
///
/// The proof is expected to be from this method on `SP1ProofWithPublicValues`:
/// https://docs.rs/sp1-sdk/latest/sp1_sdk/proof/struct.SP1ProofWithPublicValues.html#method.bytes
/// The public inputs are directly taken from the `SP1PublicValues`.
/// https://docs.rs/sp1-sdk/latest/sp1_sdk/struct.SP1PublicValues.html#method.as_slice
/// The vkey hash is derived from running `vk.bytes32()` on the program's vkey.
/// https://docs.rs/sp1-sdk/latest/sp1_sdk/trait.HashableKey.html#method.bytes32
#[inline]
pub fn verify_proof(
    proof: &[u8],
    sp1_public_inputs: &[u8],
    sp1_vkey_hash: &str,
    groth16_vk: &[u8],
) -> Result<(), Error> {
    // Hash the vk and get the first 4 bytes.
    let groth16_vk_hash: [u8; 4] = Sha256::digest(groth16_vk)[..4].try_into().unwrap();

    // 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[..4] {
        return Err(Error::Groth16VkeyHashMismatch);
    }

    let sp1_vkey_hash = decode_sp1_vkey_hash(sp1_vkey_hash)?;

    // Verify the proof.
    verify_proof_raw(
        &proof[4..],
        &groth16_public_values(&sp1_vkey_hash, sp1_public_inputs),
        groth16_vk,
    )
}