use std::{io::Write, path::Path};
use crate::{
ffi::{prove_plonk_bn254, test_plonk_bn254, verify_plonk_bn254},
witness::GnarkWitness,
PlonkBn254Proof,
};
use anyhow::Result;
use num_bigint::BigUint;
use sha2::{Digest, Sha256};
use sp1_recursion_compiler::{
constraints::Constraint,
ir::{Config, Witness},
};
#[derive(Debug, Clone)]
pub struct PlonkBn254Prover;
impl PlonkBn254Prover {
pub fn new() -> Self {
Self
}
pub fn get_vkey_hash(build_dir: &Path) -> [u8; 32] {
let vkey_path = build_dir.join("plonk_vk.bin");
let vk_bin_bytes = std::fs::read(vkey_path).unwrap();
Sha256::digest(vk_bin_bytes).into()
}
pub fn test<C: Config>(constraints: Vec<Constraint>, witness: Witness<C>) {
let serialized = serde_json::to_string(&constraints).unwrap();
let mut constraints_file = tempfile::NamedTempFile::new().unwrap();
constraints_file.write_all(serialized.as_bytes()).unwrap();
let mut witness_file = tempfile::NamedTempFile::new().unwrap();
let gnark_witness = GnarkWitness::new(witness);
let serialized = serde_json::to_string(&gnark_witness).unwrap();
witness_file.write_all(serialized.as_bytes()).unwrap();
test_plonk_bn254(
witness_file.path().to_str().unwrap(),
constraints_file.path().to_str().unwrap(),
);
}
pub fn prove<C: Config>(&self, witness: Witness<C>, build_dir: &Path) -> PlonkBn254Proof {
let mut witness_file = tempfile::NamedTempFile::new().unwrap();
let gnark_witness = GnarkWitness::new(witness);
let serialized = serde_json::to_string(&gnark_witness).unwrap();
witness_file.write_all(serialized.as_bytes()).unwrap();
let mut proof =
prove_plonk_bn254(build_dir.to_str().unwrap(), witness_file.path().to_str().unwrap());
proof.plonk_vkey_hash = Self::get_vkey_hash(build_dir);
proof
}
#[allow(clippy::too_many_arguments)]
pub fn verify(
&self,
proof: &PlonkBn254Proof,
vkey_hash: &BigUint,
committed_values_digest: &BigUint,
exit_code: &BigUint,
vk_root: &BigUint,
proof_nonce: &BigUint,
build_dir: &Path,
) -> Result<()> {
if proof.plonk_vkey_hash != Self::get_vkey_hash(build_dir) {
return Err(anyhow::anyhow!(
"Proof vkey hash does not match circuit vkey hash, it was generated with a different circuit."
));
}
verify_plonk_bn254(
build_dir
.to_str()
.ok_or_else(|| anyhow::anyhow!("Failed to convert build dir to string"))?,
&proof.raw_proof,
&vkey_hash.to_string(),
&committed_values_digest.to_string(),
&exit_code.to_string(),
&vk_root.to_string(),
&proof_nonce.to_string(),
)
.map_err(|e| anyhow::anyhow!("failed to verify proof: {e}"))
}
}
impl Default for PlonkBn254Prover {
fn default() -> Self {
Self::new()
}
}