use crate::commitment_scheme::PublicParameters;
use crate::constraint_system::TurboComposer;
use crate::error::Error;
use crate::proof_system::{Proof, Prover, ProverKey, Verifier, VerifierKey};
use alloc::vec::Vec;
#[cfg(feature = "canon")]
use canonical_derive::Canon;
use dusk_bls12_381::BlsScalar;
use dusk_bytes::{DeserializableSlice, Serializable, Write};
use dusk_jubjub::{JubJubAffine, JubJubExtended, JubJubScalar};
use rand_core::{CryptoRng, RngCore};
#[cfg(feature = "rkyv-impl")]
use bytecheck::CheckBytes;
#[cfg(feature = "rkyv-impl")]
use rkyv::{
ser::{ScratchSpace, Serializer},
Archive, Deserialize, Serialize,
};
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "canon", derive(Canon))]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Deserialize, Serialize),
archive(bound(serialize = "__S: Serializer + ScratchSpace")),
archive_attr(derive(CheckBytes))
)]
pub struct PublicInputValue(
#[cfg_attr(feature = "rkyv-impl", omit_bounds)] pub(crate) Vec<BlsScalar>,
);
impl From<BlsScalar> for PublicInputValue {
fn from(scalar: BlsScalar) -> Self {
Self(vec![scalar])
}
}
impl From<JubJubScalar> for PublicInputValue {
fn from(scalar: JubJubScalar) -> Self {
Self(vec![scalar.into()])
}
}
impl From<JubJubAffine> for PublicInputValue {
fn from(point: JubJubAffine) -> Self {
Self(vec![point.get_x(), point.get_y()])
}
}
impl From<JubJubExtended> for PublicInputValue {
fn from(point: JubJubExtended) -> Self {
JubJubAffine::from(point).into()
}
}
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Deserialize, Serialize),
archive(bound(serialize = "__S: Serializer + ScratchSpace")),
archive_attr(derive(CheckBytes))
)]
pub struct VerifierData {
#[cfg_attr(feature = "rkyv-impl", omit_bounds)]
key: VerifierKey,
#[cfg_attr(feature = "rkyv-impl", omit_bounds)]
public_inputs_indexes: Vec<usize>,
}
impl VerifierData {
pub const fn new(
key: VerifierKey,
public_inputs_indexes: Vec<usize>,
) -> Self {
Self {
key,
public_inputs_indexes,
}
}
pub const fn key(&self) -> &VerifierKey {
&self.key
}
pub fn public_inputs_indexes(&self) -> &[usize] {
&self.public_inputs_indexes
}
#[allow(unused_must_use)]
pub fn to_var_bytes(&self) -> Vec<u8> {
let mut buff = vec![
0u8;
VerifierKey::SIZE
+ u32::SIZE
+ self.public_inputs_indexes.len() * u32::SIZE
];
let mut writer = &mut buff[..];
writer.write(&self.key.to_bytes());
writer.write(&(self.public_inputs_indexes.len() as u32).to_bytes());
self.public_inputs_indexes.iter().copied().for_each(|pos| {
let _ = writer.write(&(pos as u32).to_bytes());
});
buff
}
pub fn from_slice(mut buf: &[u8]) -> Result<Self, Error> {
let key = VerifierKey::from_reader(&mut buf)?;
let pos_num = u32::from_reader(&mut buf)? as usize;
let mut public_inputs_indexes = vec![];
for _ in 0..pos_num {
public_inputs_indexes.push(u32::from_reader(&mut buf)? as usize);
}
Ok(Self {
key,
public_inputs_indexes,
})
}
}
pub trait Circuit
where
Self: Sized,
{
const CIRCUIT_ID: [u8; 32];
fn gadget(&mut self, composer: &mut TurboComposer) -> Result<(), Error>;
fn compile(
&mut self,
pub_params: &PublicParameters,
) -> Result<(ProverKey, VerifierData), Error> {
let (ck, _) = pub_params.trim(self.padded_gates())?;
let mut prover = Prover::new(b"CircuitCompilation");
self.gadget(prover.composer_mut())?;
let public_inputs_indexes =
prover.composer_mut().public_input_indexes();
prover.preprocess(&ck)?;
let mut verifier = Verifier::new(b"CircuitCompilation");
self.gadget(verifier.composer_mut())?;
verifier.preprocess(&ck)?;
Ok((
prover
.prover_key
.expect("Unexpected error. Missing ProverKey in compilation"),
VerifierData::new(
verifier.verifier_key.expect(
"Unexpected error. Missing VerifierKey in compilation",
),
public_inputs_indexes,
),
))
}
fn prove<R: RngCore + CryptoRng>(
&mut self,
pub_params: &PublicParameters,
prover_key: &ProverKey,
transcript_init: &'static [u8],
rng: &mut R,
) -> Result<Proof, Error> {
let (ck, _) = pub_params.trim(self.padded_gates())?;
let mut prover = Prover::new(transcript_init);
self.gadget(prover.composer_mut())?;
prover.prover_key = Some(prover_key.clone());
prover.prove(&ck, rng)
}
fn verify(
pub_params: &PublicParameters,
verifier_data: &VerifierData,
proof: &Proof,
public_inputs: &[PublicInputValue],
transcript_init: &'static [u8],
) -> Result<(), Error> {
verify(
pub_params,
verifier_data,
proof,
public_inputs,
transcript_init,
)
}
fn public_inputs(&self) -> Vec<PublicInputValue>;
fn padded_gates(&self) -> usize;
}
pub fn verify(
pub_params: &PublicParameters,
verifier_data: &VerifierData,
proof: &Proof,
public_inputs: &[PublicInputValue],
transcript_init: &'static [u8],
) -> Result<(), Error> {
let gates = verifier_data.key().padded_gates();
let pi_indexes = verifier_data.public_inputs_indexes();
let mut dense_pi = vec![BlsScalar::zero(); gates];
public_inputs
.iter()
.map(|pi| pi.0.clone())
.flatten()
.zip(pi_indexes.iter().cloned())
.for_each(|(value, pos)| {
dense_pi[pos] = -value;
});
let mut verifier = Verifier::new(transcript_init);
verifier.verifier_key.replace(*verifier_data.key());
let opening_key = pub_params.opening_key();
verifier.verify(proof, opening_key, &dense_pi, &pi_indexes)
}