Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SuperNova: Improved RecursiveSNARK::verify #114

Merged
merged 3 commits into from
Nov 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 76 additions & 36 deletions src/supernova/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use abomonation::Abomonation;
use abomonation_derive::Abomonation;
use ff::{Field, PrimeField};
use once_cell::sync::OnceCell;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use tracing::debug;

Expand All @@ -43,12 +44,6 @@ use circuit::{

use self::error::SuperNovaError;

pub mod error;
pub(crate) mod utils;

#[cfg(test)]
mod test;

/// A struct that manages all the digests of the primary circuits of a SuperNova instance
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CircuitDigests<G: Group> {
Expand Down Expand Up @@ -786,31 +781,69 @@ where
return Err(SuperNovaError::NovaError(NovaError::ProofVerifyError));
}

// check the (relaxed) R1CS instances public outputs.
if self.l_u_secondary.X.len() != 2 {
// Check lengths of r_primary
if self.r_U_primary.len() != self.num_augmented_circuits
|| self.r_W_primary.len() != self.num_augmented_circuits
{
debug!("r_primary length mismatch");
return Err(SuperNovaError::NovaError(NovaError::ProofVerifyError));
}

self.r_U_primary[circuit_index]
.as_ref()
.map_or(Ok(()), |U| {
if U.X.len() != 2 {
debug!("r_U_primary got instance length {:?} != {:?}", U.X.len(), 2);
// Check that there are no missing instance/witness pairs
self
.r_U_primary
.iter()
.zip(self.r_W_primary.iter())
.enumerate()
.try_for_each(|(i, (u, w))| match (u, w) {
(Some(_), Some(_)) | (None, None) => Ok(()),
_ => {
debug!("r_primary[{:?}]: mismatched instance/witness pair", i);
Err(SuperNovaError::NovaError(NovaError::ProofVerifyError))
} else {
Ok(())
}
})?;

if self.r_U_secondary.X.len() != 2 {
// check we have an instance/witness pair for the circuit_index
if self.r_U_primary[circuit_index].is_none() {
debug!(
"r_U_secondary got instance length {:?} != {:?}",
self.r_U_secondary.X.len(),
2
"r_primary[{:?}]: instance/witness pair is missing",
circuit_index
);
return Err(SuperNovaError::NovaError(NovaError::ProofVerifyError));
}

// check the (relaxed) R1CS instances public outputs.
{
for (i, r_U_primary_i) in self.r_U_primary.iter().enumerate() {
if let Some(u) = r_U_primary_i {
if u.X.len() != 2 {
debug!(
"r_U_primary[{:?}] got instance length {:?} != 2",
i,
u.X.len(),
);
return Err(SuperNovaError::NovaError(NovaError::ProofVerifyError));
}
}
}

if self.l_u_secondary.X.len() != 2 {
debug!(
"l_U_secondary got instance length {:?} != 2",
self.l_u_secondary.X.len(),
);
return Err(SuperNovaError::NovaError(NovaError::ProofVerifyError));
}

if self.r_U_secondary.X.len() != 2 {
debug!(
"r_U_secondary got instance length {:?} != 2",
self.r_U_secondary.X.len(),
);
return Err(SuperNovaError::NovaError(NovaError::ProofVerifyError));
}
}

let num_field_primary_ro = 3 // params_next, i_new, program_counter_new
+ 2 * pp[circuit_index].F_arity // zo, z1
+ (7 + 2 * pp.augmented_circuit_params_primary.get_n_limbs()); // # 1 * (7 + [X0, X1]*#num_limb)
Expand Down Expand Up @@ -846,11 +879,13 @@ where
for e in &self.zi_secondary {
hasher2.absorb(*e);
}
let default_value =
RelaxedR1CSInstance::default(&pp.ck_primary, &pp[circuit_index].r1cs_shape);
self.r_U_primary.iter().for_each(|U| {

self.r_U_primary.iter().enumerate().for_each(|(i, U)| {
U.as_ref()
.unwrap_or(&default_value)
.unwrap_or(&RelaxedR1CSInstance::default(
&pp.ck_primary,
&pp[i].r1cs_shape,
))
.absorb_in_ro(&mut hasher2);
});

Expand All @@ -875,21 +910,20 @@ where
return Err(SuperNovaError::NovaError(NovaError::ProofVerifyError));
}

// check the satisfiability of the provided `circuit_index` instance
let default_instance =
RelaxedR1CSInstance::default(&pp.ck_primary, &pp[circuit_index].r1cs_shape);
let default_witness = RelaxedR1CSWitness::default(&pp[circuit_index].r1cs_shape);
// check the satisfiability of all instance/witness pairs
let (res_r_primary, (res_r_secondary, res_l_secondary)) = rayon::join(
|| {
pp[circuit_index].r1cs_shape.is_sat_relaxed(
&pp.ck_primary,
self.r_U_primary[circuit_index]
.as_ref()
.unwrap_or(&default_instance),
self.r_W_primary[circuit_index]
.as_ref()
.unwrap_or(&default_witness),
)
self
.r_U_primary
.par_iter()
.zip(self.r_W_primary.par_iter())
.enumerate()
.try_for_each(|(i, (u, w))| {
if let (Some(u), Some(w)) = (u, w) {
pp[i].r1cs_shape.is_sat_relaxed(&pp.ck_primary, u, w)?
}
Ok(())
})
},
|| {
rayon::join(
Expand Down Expand Up @@ -1010,3 +1044,9 @@ pub fn circuit_digest<
let circuit_params = CircuitShape::new(cs.r1cs_shape(), F_arity);
circuit_params.digest()
}

pub mod error;
pub(crate) mod utils;

#[cfg(test)]
mod test;
Loading