#![warn(missing_docs)]
#![doc = concat!("```no_run\n", include_str!("../examples/hash_chain.rs"), "```")]
use ark_ff::PrimeField;
use ark_relations::gr1cs::SynthesisError;
use ark_serialize::SerializationError;
use ark_std::rand::RngCore;
use sonobe_fs::Error as FoldingError;
use sonobe_primitives::{arithmetizations::Error as ArithError, circuits::FCircuit, traits::Dummy};
use thiserror::Error;
pub mod compilers;
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
ArithError(#[from] ArithError),
#[error(transparent)]
SerializationError(#[from] SerializationError),
#[error(transparent)]
FoldingError(#[from] FoldingError),
#[error(transparent)]
SynthesisError(#[from] SynthesisError),
#[error("IVC verification failed")]
IVCVerificationFail,
}
pub trait IVC {
type Field: PrimeField;
type Config;
type PublicParam;
type ProverKey<FC: FCircuit>;
type VerifierKey<FC: FCircuit>;
type Proof<FC: FCircuit>: for<'a> Dummy<&'a Self::ProverKey<FC>>;
fn preprocess(config: Self::Config, rng: impl RngCore) -> Result<Self::PublicParam, Error>;
#[allow(clippy::type_complexity)]
fn generate_keys<FC: FCircuit<Field = Self::Field>>(
pp: Self::PublicParam,
step_circuit: &FC,
) -> Result<(Self::ProverKey<FC>, Self::VerifierKey<FC>), Error>;
#[allow(clippy::type_complexity, clippy::too_many_arguments)]
fn prove<FC: FCircuit<Field = Self::Field>>(
pk: &Self::ProverKey<FC>,
step_circuit: &FC,
i: usize,
initial_state: &FC::State,
current_state: &FC::State,
external_inputs: FC::ExternalInputs,
current_proof: &Self::Proof<FC>,
rng: impl RngCore,
) -> Result<(FC::State, FC::ExternalOutputs, Self::Proof<FC>), Error>;
fn verify<FC: FCircuit<Field = Self::Field>>(
vk: &Self::VerifierKey<FC>,
i: usize,
initial_state: &FC::State,
current_state: &FC::State,
proof: &Self::Proof<FC>,
) -> Result<(), Error>;
}
pub struct IVCStatefulProver<'a, FC: FCircuit<Field = I::Field>, I: IVC> {
pk: &'a I::ProverKey<FC>,
step_circuit: &'a FC,
pub i: usize,
pub initial_state: FC::State,
pub current_state: FC::State,
pub current_proof: I::Proof<FC>,
}
impl<'a, FC: FCircuit<Field = I::Field>, I: IVC> IVCStatefulProver<'a, FC, I> {
pub fn new(
pk: &'a I::ProverKey<FC>,
step_circuit: &'a FC,
initial_state: FC::State,
) -> Result<Self, Error> {
Ok(Self {
step_circuit,
i: 0,
current_state: initial_state.clone(),
initial_state,
current_proof: I::Proof::dummy(pk),
pk,
})
}
pub fn prove_step(
&mut self,
external_inputs: FC::ExternalInputs,
rng: impl RngCore,
) -> Result<FC::ExternalOutputs, Error> {
let (next_state, external_outputs, next_proof) = I::prove(
self.pk,
self.step_circuit,
self.i,
&self.initial_state,
&self.current_state,
external_inputs,
&self.current_proof,
rng,
)?;
self.i += 1;
self.current_state = next_state;
self.current_proof = next_proof;
Ok(external_outputs)
}
}
pub trait Decider {
type IVC: IVC;
type ProverKey;
type VerifierKey;
type Instance;
type Witness;
type Proof;
fn preprocess_and_generate_keys<FC: FCircuit<Field = <Self::IVC as IVC>::Field>>(
ivc_pk: &<Self::IVC as IVC>::ProverKey<FC>,
rng: impl RngCore,
) -> Result<(Self::ProverKey, Self::VerifierKey), Error>;
fn prove(
pk: &Self::ProverKey,
w: &Self::Witness,
x: &Self::Instance,
rng: impl RngCore,
) -> Result<Self::Proof, Error>;
fn verify(vk: &Self::VerifierKey, x: &Self::Instance, proof: &Self::Proof)
-> Result<(), Error>;
}
#[cfg(test)]
mod tests {
use ark_std::{error::Error, rand::Rng};
use super::*;
pub fn test_ivc<I: IVC, F: FCircuit<Field = I::Field>>(
config: I::Config,
step_circuit: F,
external_inputs_vec: Vec<F::ExternalInputs>,
mut rng: impl Rng,
) -> Result<(), Box<dyn Error>> {
let pp = I::preprocess(config, &mut rng)?;
let (pk, vk) = I::generate_keys(pp, &step_circuit)?;
let initial_state = step_circuit.dummy_state();
let mut prover = IVCStatefulProver::<_, I>::new(&pk, &step_circuit, initial_state)?;
for external_inputs in external_inputs_vec {
prover.prove_step(external_inputs, &mut rng)?;
I::verify(
&vk,
prover.i,
&prover.initial_state,
&prover.current_state,
&prover.current_proof,
)?;
}
Ok(())
}
}