use std::string::String;
use std::vec::Vec;
use halo2_proofs::{
pasta::EqAffine,
plonk::{self, keygen_pk, keygen_vk, verify_proof, SingleVerifier},
poly::commitment::Params,
transcript::{Blake2bRead, Challenge255},
};
use crate::prove_error::create_proof_bytes;
use crate::ProveError;
use super::circuit::{Circuit, Instance, K};
pub type ShareRevealKeys = (
Params<EqAffine>,
plonk::ProvingKey<EqAffine>,
plonk::VerifyingKey<EqAffine>,
);
static SHARE_REVEAL_PK_CACHE: std::sync::OnceLock<Result<ShareRevealKeys, String>> =
std::sync::OnceLock::new();
pub fn share_reveal_params() -> Params<EqAffine> {
Params::new(K)
}
pub fn share_reveal_proving_key(
params: &Params<EqAffine>,
) -> Result<(plonk::ProvingKey<EqAffine>, plonk::VerifyingKey<EqAffine>), ProveError> {
let empty_circuit = Circuit::default();
let vk = keygen_vk(params, &empty_circuit).map_err(ProveError::KeygenVk)?;
let pk = keygen_pk(params, vk.clone(), &empty_circuit).map_err(ProveError::KeygenPk)?;
Ok((pk, vk))
}
pub fn share_reveal_cached_keys() -> Result<&'static ShareRevealKeys, ProveError> {
match SHARE_REVEAL_PK_CACHE.get_or_init(|| {
let params = share_reveal_params();
share_reveal_proving_key(¶ms)
.map(|(pk, vk)| (params, pk, vk))
.map_err(|error| error.to_string())
}) {
Ok(keys) => Ok(keys),
Err(error) => Err(ProveError::CachedKeygen(error.clone())),
}
}
pub fn warm_share_reveal_keys() -> Result<(), ProveError> {
share_reveal_cached_keys().map(|_| ())
}
pub fn create_share_reveal_proof(
circuit: Circuit,
instance: &Instance,
) -> Result<Vec<u8>, ProveError> {
let (params, pk, _vk) = share_reveal_cached_keys()?;
let public_inputs = instance.to_halo2_instance();
create_proof_bytes(params, pk, circuit, &public_inputs)
}
pub fn verify_share_reveal_proof(proof: &[u8], instance: &Instance) -> Result<(), String> {
let (params, _pk, vk) = share_reveal_cached_keys().map_err(|error| error.to_string())?;
let public_inputs = instance.to_halo2_instance();
let strategy = SingleVerifier::new(params);
let mut transcript = Blake2bRead::<_, EqAffine, Challenge255<_>>::init(proof);
verify_proof(params, vk, strategy, &[&[&public_inputs]], &mut transcript)
.map_err(|e| format!("share_reveal verification failed: {:?}", e))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ProveError;
use halo2_proofs::plonk;
use pasta_curves::pallas;
fn minimal_instance() -> Instance {
Instance::from_parts(
pallas::Base::from(1),
pallas::Base::from(2),
pallas::Base::from(3),
pallas::Base::from(4),
pallas::Base::from(5),
pallas::Base::from(6),
pallas::Base::from(7),
pallas::Base::from(8),
pallas::Base::from(9),
)
}
#[test]
fn create_share_reveal_proof_signature_returns_result() {
let _: fn(Circuit, &Instance) -> Result<Vec<u8>, ProveError> = create_share_reveal_proof;
}
#[test]
fn create_share_reveal_proof_returns_err_for_missing_witnesses() {
let instance = minimal_instance();
let err = create_share_reveal_proof(Circuit::default(), &instance).unwrap_err();
assert!(matches!(err, ProveError::Halo2(plonk::Error::Synthesis)));
}
}