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

Return ZK #380

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
35 changes: 26 additions & 9 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
traits::{
circuit::StepCircuit, commitment::CommitmentTrait, Engine, ROCircuitTrait, ROConstantsCircuit,
},
Commitment,
Commitment, StepCounterType,
};
use abomonation_derive::Abomonation;
use bellpepper::gadgets::{boolean_utils::conditionally_select_slice, Assignment};
Expand Down Expand Up @@ -260,6 +260,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
cs: &mut CS,
) -> Result<Vec<AllocatedNum<E::Base>>, SynthesisError> {
let arity = self.step_circuit.arity();
let counter_type = self.step_circuit.get_counter_type();

// Allocate all witnesses
let (params, i, z_0, z_i, U, u, T) =
Expand Down Expand Up @@ -307,15 +308,31 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
)?;

// Compute i + 1
let i_new = AllocatedNum::alloc(cs.namespace(|| "i + 1"), || {
Ok(*i.get_value().get()? + E::Base::ONE)
let i_new = AllocatedNum::alloc(cs.namespace(|| "next i"), || match counter_type {
StepCounterType::Incremental => Ok(*i.get_value().get()? + E::Base::ONE),
StepCounterType::External => {
let inc = *is_base_case.get_value().get()? as u64;
Ok(*i.get_value().get()? + E::Base::from(inc))
}
})?;
cs.enforce(
|| "check i + 1",
|lc| lc,
|lc| lc,
|lc| lc + i_new.get_variable() - CS::one() - i.get_variable(),
);
match counter_type {
StepCounterType::Incremental => {
cs.enforce(
|| "check i + 1",
|lc| lc,
|lc| lc,
|lc| lc + i_new.get_variable() - CS::one() - i.get_variable(),
);
}
StepCounterType::External => {
cs.enforce(
|| "check i + 1 base",
|lc| lc,
|lc| lc,
|lc| lc + i_new.get_variable() - is_base_case.get_variable() - i.get_variable(),
);
}
}

// Compute z_{i+1}
let z_input = conditionally_select_slice(
Expand Down
13 changes: 9 additions & 4 deletions src/cyclefold/nifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

use std::marker::PhantomData;

use rand_core::OsRng;
use ff::Field;

use crate::{
constants::{NIO_CYCLE_FOLD, NUM_CHALLENGE_BITS, NUM_FE_IN_EMULATED_POINT},
errors::NovaError,
Expand Down Expand Up @@ -66,15 +69,16 @@ where

absorb_primary_r1cs::<E1, E2>(U2, &mut ro);

let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2)?;
let r_T = E1::Scalar::random(&mut OsRng);
let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2, &r_T)?;

absorb_primary_commitment::<E1, E2>(&comm_T, &mut ro);

let r = scalar_as_base::<E2>(ro.squeeze(NUM_CHALLENGE_BITS));

let U = U1.fold(U2, &comm_T, &r);

let W = W1.fold(W2, &T, &r)?;
let W = W1.fold(W2, &T, &r_T, &r)?;

Ok((
Self {
Expand Down Expand Up @@ -131,7 +135,8 @@ impl<E: Engine> CycleFoldNIFS<E> {
absorb_cyclefold_r1cs(U2, &mut ro);

// compute a commitment to the cross-term
let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2)?;
let r_T = E::Scalar::random(&mut OsRng);
let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2, &r_T)?;

// append `comm_T` to the transcript and obtain a challenge
comm_T.absorb_in_ro(&mut ro);
Expand All @@ -143,7 +148,7 @@ impl<E: Engine> CycleFoldNIFS<E> {
let U = U1.fold(U2, &comm_T, &r);

// fold the witness using `r` and `T`
let W = W1.fold(W2, &T, &r)?;
let W = W1.fold(W2, &T, &r_T, &r)?;

// return the folded instance and witness
Ok((
Expand Down
18 changes: 18 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub enum NovaError {
/// returned if the supplied witness is not a satisfying witness to a given shape and instance, with error constraint index
#[error("UnSatIndex")]
UnSatIndex(usize),
/// returned if the counter types for the primary and secondary circuit are not the same
#[error("MismatchedCounterType")]
MismatchedCounterType,
/// returned when the supplied compressed commitment cannot be decompressed
#[error("DecompressionError")]
DecompressionError,
Expand All @@ -40,9 +43,24 @@ pub enum NovaError {
/// returned if there is an error in the proof/verification of a PCS
#[error("PCSError")]
PCSError(#[from] PCSError),
/// returned when an invalid knowledge proof is returned
#[error("InvalidZkKnowledgeProof")]
InvalidZkKnowledgeProof,
/// returned when an invalid equality proof is returned
#[error("InvalidZkEqualityProof")]
InvalidZkEqualityProof,
/// returned when an invalid product proof is returned
#[error("InvalidZkProductProof")]
InvalidZkProductProof,
/// returned when an invalid dot product proof (schnorr) is provided
#[error("InvalidZkDotProductProof")]
InvalidZkDotProductProof,
/// returned when an invalid sum-check proof is provided
#[error("InvalidSumcheckProof")]
InvalidSumcheckProof,
/// InvalidIPA
#[error("InvalidIPA")]
InvalidIPA,
/// returned when the initial input to an incremental computation differs from a previously declared arity
#[error("InvalidInitialInputLength")]
InvalidInitialInputLength,
Expand Down
69 changes: 57 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This library implements Nova, a high-speed recursive SNARK.
#![deny(
warnings,
unused,
// warnings,
// unused,
future_incompatible,
nonstandard_style,
rust_2018_idioms,
Expand Down Expand Up @@ -61,6 +61,19 @@ use traits::{
AbsorbInROTrait, Engine, ROConstants, ROConstantsCircuit, ROTrait,
};

/// The type of counter used to measure the progress of the recusrive computation
#[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize, Deserialize)]
pub enum StepCounterType {
/// Incremental counter is a standard monotonically increasing integer
Incremental,
/// External counter introduces completion that is defined outside of the circuit
External,
}

/// When using Extenral Step counter type, the verifier should use
/// `FINAL_EXTERNAL_COUNTER` as the number of steps of execution.
pub const FINAL_EXTERNAL_COUNTER: usize = 1;

/// A type that holds parameters for the primary and secondary circuits of Nova and SuperNova
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Abomonation)]
#[serde(bound = "")]
Expand Down Expand Up @@ -97,6 +110,7 @@ where
{
F_arity_primary: usize,
F_arity_secondary: usize,
counter_type: StepCounterType,
ro_consts_primary: ROConstants<E>,
ro_consts_circuit_primary: ROConstantsCircuit<Dual<E>>,
ck_primary: Arc<CommitmentKey<E>>,
Expand Down Expand Up @@ -261,6 +275,13 @@ where
let F_arity_primary = c_primary.arity();
let F_arity_secondary = c_secondary.arity();

let step_counter_primary = c_primary.get_counter_type();
let step_counter_secondary = c_secondary.get_counter_type();

if step_counter_primary != step_counter_secondary {
return Err(NovaError::MismatchedCounterType);
}

// ro_consts_circuit_primary are parameterized by E2 because the type alias uses E2::Base = E1::Scalar
let ro_consts_circuit_primary: ROConstantsCircuit<Dual<E1>> =
ROConstantsCircuit::<Dual<E1>>::default();
Expand Down Expand Up @@ -300,6 +321,7 @@ where
Ok(Self {
F_arity_primary,
F_arity_secondary,
counter_type: step_counter_primary,
ro_consts_primary,
ro_consts_circuit_primary,
ck_primary,
Expand All @@ -323,6 +345,11 @@ where
.expect("Failure in retrieving digest")
}

/// Returns the type of the counter for this circuit
pub fn get_counter_type(&self) -> StepCounterType {
self.counter_type
}

/// Returns the number of constraints in the primary and secondary circuits
pub const fn num_constraints(&self) -> (usize, usize) {
(
Expand Down Expand Up @@ -538,6 +565,8 @@ where
let r_U_secondary_i = self.r_U_secondary.clone();
let l_u_secondary_i = self.l_u_secondary.clone();

let counter_type = pp.get_counter_type();

// fold the secondary circuit's instance
let (nifs_secondary, _) = NIFS::prove_mut(
&*pp.ck_secondary,
Expand Down Expand Up @@ -633,7 +662,12 @@ where
self.l_u_secondary = l_u_secondary;
self.l_w_secondary = l_w_secondary;

self.i += 1;
// self.i += 1;

match counter_type {
StepCounterType::Incremental => self.i += 1,
StepCounterType::External => self.i = 1,
};

Ok(())
}
Expand All @@ -646,11 +680,26 @@ where
z0_primary: &[E1::Scalar],
z0_secondary: &[<Dual<E1> as Engine>::Scalar],
) -> Result<(Vec<E1::Scalar>, Vec<<Dual<E1> as Engine>::Scalar>), NovaError> {
// number of steps cannot be zero
let is_num_steps_zero = num_steps == 0;
let counter_type = pp.get_counter_type();

// If counter_type is External, the number of invocations
// is irrevelant since progress is measured externally.
// If it is Incremental, then it should have been executed it
// num_steps, and num_steps should be non-zero.
match counter_type {
StepCounterType::External => {}
StepCounterType::Incremental => {
// number of steps cannot be zero
if num_steps == 0 {
return Err(NovaError::ProofVerifyError);
}

// check if the provided proof has executed num_steps
let is_num_steps_not_match = self.i != num_steps;
// check if the provided proof has executed num_steps
if self.i != num_steps {
return Err(NovaError::ProofVerifyError);
}
}
}

// check if the initial inputs match
let is_inputs_not_match = self.z0_primary != z0_primary || self.z0_secondary != z0_secondary;
Expand All @@ -660,11 +709,7 @@ where
|| self.r_U_primary.X.len() != 2
|| self.r_U_secondary.X.len() != 2;

if is_num_steps_zero
|| is_num_steps_not_match
|| is_inputs_not_match
|| is_instance_has_two_outputs
{
if is_inputs_not_match || is_instance_has_two_outputs {
return Err(NovaError::ProofVerifyError);
}

Expand Down
10 changes: 7 additions & 3 deletions src/nifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::{
traits::{commitment::CommitmentTrait, AbsorbInROTrait, Engine, ROConstants, ROTrait},
Commitment, CommitmentKey, CompressedCommitment,
};
use ff::Field;
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};

/// A SNARK that holds the proof of a step of an incremental computation
Expand Down Expand Up @@ -72,7 +74,8 @@ impl<E: Engine> NIFS<E> {
U2.absorb_in_ro(&mut ro);

// compute a commitment to the cross-term
let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2)?;
let r_T = E::Scalar::random(&mut OsRng);
let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2, &r_T)?;

// append `comm_T` to the transcript and obtain a challenge
comm_T.absorb_in_ro(&mut ro);
Expand All @@ -84,7 +87,7 @@ impl<E: Engine> NIFS<E> {
let U = U1.fold(U2, &comm_T, &r);

// fold the witness using `r` and `T`
let W = W1.fold(W2, &T, &r)?;
let W = W1.fold(W2, &T, &r_T, &r)?;

// return the folded instance and witness
Ok((
Expand Down Expand Up @@ -126,7 +129,8 @@ impl<E: Engine> NIFS<E> {
U2.absorb_in_ro(&mut ro);

// compute a commitment to the cross-term
let comm_T = S.commit_T_into(ck, U1, W1, U2, W2, T, ABC_Z_1, ABC_Z_2)?;
let r_T = E::Scalar::random(&mut OsRng);
let comm_T = S.commit_T_into(ck, U1, W1, U2, W2, T, ABC_Z_1, ABC_Z_2, &r_T)?;

// append `comm_T` to the transcript and obtain a challenge
comm_T.absorb_in_ro(&mut ro);
Expand Down
2 changes: 1 addition & 1 deletion src/provider/bn256_grumpkin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
};
use digest::{ExtendableOutput, Update};
use ff::{FromUniformBytes, PrimeField};
use group::{cofactor::CofactorCurveAffine, Curve, Group as AnotherGroup};
use group::{cofactor::CofactorCurveAffine, Curve, Group as AnotherGroup, GroupEncoding};
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use grumpkin_msm::{bn256 as bn256_msm, grumpkin as grumpkin_msm};
// Remove this when https://github.com/zcash/pasta_curves/issues/41 resolves
Expand Down
Loading
Loading