use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{UniformRand, rand::RngCore, sync::Arc};
use sonobe_primitives::{
arithmetizations::{
Arith, ArithConfig, ArithRelation,
r1cs::{RelaxedInstance, RelaxedWitness},
},
circuits::AssignmentsOwned,
commitments::{CommitmentDef, CommitmentOps},
relations::{Relation, WitnessInstanceSampler},
};
use super::{
instances::{IncomingInstance as IU, RunningInstance as RU},
witnesses::{IncomingWitness as IW, RunningWitness as RW},
};
use crate::{DeciderKey, Error, PlainInstance as PU, PlainWitness as PW};
#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct NovaKey<A: Arith, CM: CommitmentDef> {
pub(super) arith: Arc<A>,
pub(super) ck: Arc<CM::Key>,
}
impl<A: Arith, CM: CommitmentDef> DeciderKey for NovaKey<A, CM> {
type ProverKey = Self;
type VerifierKey = ();
fn to_pk(&self) -> &Self::ProverKey {
self
}
fn to_vk(&self) -> &Self::VerifierKey {
&()
}
fn to_arith_config(&self) -> ArithConfig {
self.arith.config()
}
}
impl<A, CM> Relation<RW<CM>, RU<CM>> for NovaKey<A, CM>
where
A: for<'a> ArithRelation<RelaxedWitness<&'a [CM::Scalar]>, RelaxedInstance<&'a [CM::Scalar]>>,
CM: CommitmentOps,
{
type Error = Error;
fn check_relation(&self, w: &RW<CM>, u: &RU<CM>) -> Result<(), Self::Error> {
self.arith.check_relation(
&RelaxedWitness { w: &w.w, e: &w.e },
&RelaxedInstance { x: &u.x, u: &u.u },
)?;
CM::open(&self.ck, &w.w, &w.r_w, &u.cm_w)?;
CM::open(&self.ck, &w.e, &w.r_e, &u.cm_e)?;
Ok(())
}
}
impl<A, CM> Relation<IW<CM>, IU<CM>> for NovaKey<A, CM>
where
A: ArithRelation<Vec<CM::Scalar>, Vec<CM::Scalar>>,
CM: CommitmentOps,
{
type Error = Error;
fn check_relation(&self, w: &IW<CM>, u: &IU<CM>) -> Result<(), Self::Error> {
self.arith.check_relation(&w.w, &u.x)?;
CM::open(&self.ck, &w.w, &w.r_w, &u.cm_w)?;
Ok(())
}
}
impl<A, CM> Relation<PW<CM::Scalar>, PU<CM::Scalar>> for NovaKey<A, CM>
where
A: ArithRelation<Vec<CM::Scalar>, Vec<CM::Scalar>>,
CM: CommitmentDef,
{
type Error = Error;
fn check_relation(&self, w: &PW<CM::Scalar>, u: &PU<CM::Scalar>) -> Result<(), Self::Error> {
self.arith.check_relation(w, u)?;
Ok(())
}
}
impl<A: Arith, CM: CommitmentOps> WitnessInstanceSampler<IW<CM>, IU<CM>> for NovaKey<A, CM> {
type Source = AssignmentsOwned<CM::Scalar>;
type Error = Error;
fn sample(&self, z: Self::Source, rng: impl RngCore) -> Result<(IW<CM>, IU<CM>), Error> {
let (w, x) = (z.private, z.public);
let (cm_w, r_w) = CM::commit(&self.ck, &w, rng)?;
Ok((IW { w, r_w }, IU { cm_w, x }))
}
}
impl<A: Arith, CM: CommitmentDef> WitnessInstanceSampler<PW<CM::Scalar>, PU<CM::Scalar>>
for NovaKey<A, CM>
{
type Source = AssignmentsOwned<CM::Scalar>;
type Error = Error;
fn sample(
&self,
z: Self::Source,
_rng: impl RngCore,
) -> Result<(PW<CM::Scalar>, PU<CM::Scalar>), Error> {
Ok((z.private.into(), z.public.into()))
}
}
impl<A, CM> WitnessInstanceSampler<RW<CM>, RU<CM>> for NovaKey<A, CM>
where
A: for<'a> ArithRelation<
RelaxedWitness<&'a [CM::Scalar]>,
RelaxedInstance<&'a [CM::Scalar]>,
Evaluation = Vec<CM::Scalar>,
>,
CM: CommitmentOps,
{
type Source = ();
type Error = Error;
fn sample(&self, _: Self::Source, mut rng: impl RngCore) -> Result<(RW<CM>, RU<CM>), Error> {
let cfg = self.arith.config();
let u = CM::Scalar::rand(&mut rng);
let x = (0..cfg.n_public_inputs)
.map(|_| CM::Scalar::rand(&mut rng))
.collect::<Vec<_>>();
let w = (0..cfg.n_witnesses)
.map(|_| CM::Scalar::rand(&mut rng))
.collect::<Vec<_>>();
let e = self.arith.eval_relation(
&RelaxedWitness { w: &w, e: &[] },
&RelaxedInstance { x: &x, u: &u },
)?;
let (cm_w, r_w) = CM::commit(&self.ck, &w, &mut rng)?;
let (cm_e, r_e) = CM::commit(&self.ck, &e, &mut rng)?;
Ok((RW { w, r_w, e, r_e }, RU { cm_w, x, cm_e, u }))
}
}