mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-28 14:56:40 +01:00
Enable hiding commitments in nova and hypernova (#129)
* feat: enable hiding commitments in nova and hypernova * fix: set blinding values for witness vector * fix: remove cloning of the cyclefold running instance * fix: do not re-use blinding values between prove steps * fix: specify whether the witness should use blinding values using a const generic * feat: create a `dummy` method for nova witnesses as well * chore: clippy - removed unused imports
This commit is contained in:
@@ -81,10 +81,10 @@ where
|
||||
for<'b> &'b GC1: GroupOpsBounds<'b, C1, GC1>,
|
||||
for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>,
|
||||
// constrain FS into Nova, since this is a Decider specifically for Nova
|
||||
Nova<C1, GC1, C2, GC2, FC, CS1, CS2>: From<FS>,
|
||||
crate::folding::nova::ProverParams<C1, C2, CS1, CS2>:
|
||||
Nova<C1, GC1, C2, GC2, FC, CS1, CS2, false>: From<FS>,
|
||||
crate::folding::nova::ProverParams<C1, C2, CS1, CS2, false>:
|
||||
From<<FS as FoldingScheme<C1, C2, FC>>::ProverParam>,
|
||||
crate::folding::nova::VerifierParams<C1, C2, CS1, CS2>:
|
||||
crate::folding::nova::VerifierParams<C1, C2, CS1, CS2, false>:
|
||||
From<<FS as FoldingScheme<C1, C2, FC>>::VerifierParam>,
|
||||
{
|
||||
type PreprocessorParam = (FS::ProverParam, FS::VerifierParam);
|
||||
@@ -108,14 +108,17 @@ where
|
||||
|
||||
// get the FoldingScheme prover & verifier params from Nova
|
||||
#[allow(clippy::type_complexity)]
|
||||
let nova_pp:
|
||||
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::ProverParam =
|
||||
prep_param.0.clone().into()
|
||||
;
|
||||
let nova_pp: <Nova<C1, GC1, C2, GC2, FC, CS1, CS2, false> as FoldingScheme<
|
||||
C1,
|
||||
C2,
|
||||
FC,
|
||||
>>::ProverParam = prep_param.0.clone().into();
|
||||
#[allow(clippy::type_complexity)]
|
||||
let nova_vp:
|
||||
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::VerifierParam =
|
||||
prep_param.1.clone().into();
|
||||
let nova_vp: <Nova<C1, GC1, C2, GC2, FC, CS1, CS2, false> as FoldingScheme<
|
||||
C1,
|
||||
C2,
|
||||
FC,
|
||||
>>::VerifierParam = prep_param.1.clone().into();
|
||||
let pp_hash = nova_vp.pp_hash()?;
|
||||
|
||||
let pp = (g16_pk, nova_pp.cs_pp);
|
||||
@@ -338,6 +341,7 @@ pub mod tests {
|
||||
CubicFCircuit<Fr>,
|
||||
KZG<'static, Bn254>,
|
||||
Pedersen<Projective2>,
|
||||
false,
|
||||
>;
|
||||
type D = Decider<
|
||||
Projective,
|
||||
|
||||
@@ -193,14 +193,14 @@ where
|
||||
/// Circuit that implements the in-circuit checks needed for the onchain (Ethereum's EVM)
|
||||
/// verification.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeciderEthCircuit<C1, GC1, C2, GC2, CS1, CS2>
|
||||
pub struct DeciderEthCircuit<C1, GC1, C2, GC2, CS1, CS2, const H: bool = false>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
{
|
||||
_c1: PhantomData<C1>,
|
||||
_gc1: PhantomData<GC1>,
|
||||
@@ -246,25 +246,25 @@ where
|
||||
pub eval_W: Option<C1::ScalarField>,
|
||||
pub eval_E: Option<C1::ScalarField>,
|
||||
}
|
||||
impl<C1, GC1, C2, GC2, CS1, CS2> DeciderEthCircuit<C1, GC1, C2, GC2, CS1, CS2>
|
||||
impl<C1, GC1, C2, GC2, CS1, CS2, const H: bool> DeciderEthCircuit<C1, GC1, C2, GC2, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
// enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider
|
||||
CS2: CommitmentScheme<C2, ProverParams = PedersenParams<C2>>,
|
||||
CS2: CommitmentScheme<C2, H, ProverParams = PedersenParams<C2>>,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
{
|
||||
pub fn from_nova<FC: FCircuit<C1::ScalarField>>(
|
||||
nova: Nova<C1, GC1, C2, GC2, FC, CS1, CS2>,
|
||||
nova: Nova<C1, GC1, C2, GC2, FC, CS1, CS2, H>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut transcript = PoseidonSponge::<C1::ScalarField>::new(&nova.poseidon_config);
|
||||
|
||||
// compute the U_{i+1}, W_{i+1}
|
||||
let (T, cmT) = NIFS::<C1, CS1>::compute_cmT(
|
||||
let (T, cmT) = NIFS::<C1, CS1, H>::compute_cmT(
|
||||
&nova.cs_pp,
|
||||
&nova.r1cs.clone(),
|
||||
&nova.w_i.clone(),
|
||||
@@ -281,7 +281,7 @@ where
|
||||
);
|
||||
let r_Fr = C1::ScalarField::from_bigint(BigInteger::from_bits_le(&r_bits))
|
||||
.ok_or(Error::OutOfBounds)?;
|
||||
let (W_i1, U_i1) = NIFS::<C1, CS1>::fold_instances(
|
||||
let (W_i1, U_i1) = NIFS::<C1, CS1, H>::fold_instances(
|
||||
r_Fr, &nova.W_i, &nova.U_i, &nova.w_i, &nova.u_i, &T, cmT,
|
||||
)?;
|
||||
|
||||
@@ -376,8 +376,8 @@ where
|
||||
})?;
|
||||
|
||||
let u_dummy_native = CommittedInstance::<C1>::dummy(2);
|
||||
let w_dummy_native = Witness::<C1>::new(
|
||||
vec![C1::ScalarField::zero(); self.r1cs.A.n_cols - 3 /* (3=2+1, since u_i.x.len=2) */],
|
||||
let w_dummy_native = Witness::<C1>::dummy(
|
||||
self.r1cs.A.n_cols - 3, /* (3=2+1, since u_i.x.len=2) */
|
||||
self.E_len,
|
||||
);
|
||||
|
||||
@@ -453,10 +453,8 @@ where
|
||||
use ark_r1cs_std::ToBitsGadget;
|
||||
|
||||
let cf_u_dummy_native = CommittedInstance::<C2>::dummy(cf_io_len(NOVA_CF_N_POINTS));
|
||||
let w_dummy_native = Witness::<C2>::new(
|
||||
vec![C2::ScalarField::zero(); self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l],
|
||||
self.cf_E_len,
|
||||
);
|
||||
let w_dummy_native =
|
||||
Witness::<C2>::dummy(self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l, self.cf_E_len);
|
||||
let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || {
|
||||
Ok(self.cf_U_i.unwrap_or_else(|| cf_u_dummy_native.clone()))
|
||||
})?;
|
||||
@@ -788,6 +786,7 @@ pub mod tests {
|
||||
CubicFCircuit<Fr>,
|
||||
Pedersen<Projective>,
|
||||
Pedersen<Projective2>,
|
||||
false,
|
||||
>;
|
||||
|
||||
let prep_param = PreprocessorParam::<
|
||||
@@ -796,6 +795,7 @@ pub mod tests {
|
||||
CubicFCircuit<Fr>,
|
||||
Pedersen<Projective>,
|
||||
Pedersen<Projective2>,
|
||||
false,
|
||||
>::new(poseidon_config, F_circuit);
|
||||
let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use ark_std::fmt::Debug;
|
||||
use ark_std::rand::RngCore;
|
||||
use ark_std::{One, Zero};
|
||||
use ark_std::{One, UniformRand, Zero};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::commitment::CommitmentScheme;
|
||||
@@ -166,17 +166,37 @@ impl<C: CurveGroup> Witness<C>
|
||||
where
|
||||
<C as Group>::ScalarField: Absorb,
|
||||
{
|
||||
pub fn new(w: Vec<C::ScalarField>, e_len: usize) -> Self {
|
||||
// note: at the current version, we don't use the blinding factors and we set them to 0
|
||||
// always.
|
||||
pub fn new<const H: bool>(w: Vec<C::ScalarField>, e_len: usize, mut rng: impl RngCore) -> Self {
|
||||
let (rW, rE) = if H {
|
||||
(
|
||||
C::ScalarField::rand(&mut rng),
|
||||
C::ScalarField::rand(&mut rng),
|
||||
)
|
||||
} else {
|
||||
(C::ScalarField::zero(), C::ScalarField::zero())
|
||||
};
|
||||
|
||||
Self {
|
||||
E: vec![C::ScalarField::zero(); e_len],
|
||||
rE: C::ScalarField::zero(),
|
||||
rE,
|
||||
W: w,
|
||||
rW: C::ScalarField::zero(),
|
||||
rW,
|
||||
}
|
||||
}
|
||||
pub fn commit<CS: CommitmentScheme<C>>(
|
||||
|
||||
pub fn dummy(w_len: usize, e_len: usize) -> Self {
|
||||
let (rW, rE) = (C::ScalarField::zero(), C::ScalarField::zero());
|
||||
let w = vec![C::ScalarField::zero(); w_len];
|
||||
|
||||
Self {
|
||||
E: vec![C::ScalarField::zero(); e_len],
|
||||
rE,
|
||||
W: w,
|
||||
rW,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit<CS: CommitmentScheme<C, HC>, const HC: bool>(
|
||||
&self,
|
||||
params: &CS::ProverParams,
|
||||
x: Vec<C::ScalarField>,
|
||||
@@ -196,13 +216,13 @@ where
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2>
|
||||
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2, const H: bool>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
{
|
||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||
pub F: FC,
|
||||
@@ -213,13 +233,13 @@ where
|
||||
pub cf_cs_vp: Option<CS2::VerifierParams>,
|
||||
}
|
||||
|
||||
impl<C1, C2, FC, CS1, CS2> PreprocessorParam<C1, C2, FC, CS1, CS2>
|
||||
impl<C1, C2, FC, CS1, CS2, const H: bool> PreprocessorParam<C1, C2, FC, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
{
|
||||
pub fn new(poseidon_config: PoseidonConfig<C1::ScalarField>, F: FC) -> Self {
|
||||
Self {
|
||||
@@ -234,12 +254,12 @@ where
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProverParams<C1, C2, CS1, CS2>
|
||||
pub struct ProverParams<C1, C2, CS1, CS2, const H: bool>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
{
|
||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||
pub cs_pp: CS1::ProverParams,
|
||||
@@ -247,12 +267,12 @@ where
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VerifierParams<C1, C2, CS1, CS2>
|
||||
pub struct VerifierParams<C1, C2, CS1, CS2, const H: bool>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
{
|
||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||
pub r1cs: R1CS<C1::ScalarField>,
|
||||
@@ -261,16 +281,16 @@ where
|
||||
pub cf_cs_vp: CS2::VerifierParams,
|
||||
}
|
||||
|
||||
impl<C1, C2, CS1, CS2> VerifierParams<C1, C2, CS1, CS2>
|
||||
impl<C1, C2, CS1, CS2, const H: bool> VerifierParams<C1, C2, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
{
|
||||
/// returns the hash of the public parameters of Nova
|
||||
pub fn pp_hash(&self) -> Result<C1::ScalarField, Error> {
|
||||
pp_hash::<C1, C2, CS1, CS2>(
|
||||
pp_hash::<C1, C2, CS1, CS2, H>(
|
||||
&self.r1cs,
|
||||
&self.cf_r1cs,
|
||||
&self.cs_vp,
|
||||
@@ -282,16 +302,17 @@ where
|
||||
|
||||
/// Implements Nova+CycleFold's IVC, described in [Nova](https://eprint.iacr.org/2021/370.pdf) and
|
||||
/// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait
|
||||
/// The `H` const generic specifies whether the homorphic commitment scheme is blinding
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
pub struct Nova<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool = false>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
{
|
||||
_gc1: PhantomData<GC1>,
|
||||
_c2: PhantomData<C2>,
|
||||
@@ -325,16 +346,16 @@ where
|
||||
pub cf_U_i: CommittedInstance<C2>,
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> FoldingScheme<C1, C2, FC>
|
||||
for Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> FoldingScheme<C1, C2, FC>
|
||||
for Nova<C1, GC1, C2, GC2, FC, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
@@ -343,9 +364,9 @@ where
|
||||
for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
|
||||
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
||||
{
|
||||
type PreprocessorParam = PreprocessorParam<C1, C2, FC, CS1, CS2>;
|
||||
type ProverParam = ProverParams<C1, C2, CS1, CS2>;
|
||||
type VerifierParam = VerifierParams<C1, C2, CS1, CS2>;
|
||||
type PreprocessorParam = PreprocessorParam<C1, C2, FC, CS1, CS2, H>;
|
||||
type ProverParam = ProverParams<C1, C2, CS1, CS2, H>;
|
||||
type VerifierParam = VerifierParams<C1, C2, CS1, CS2, H>;
|
||||
type RunningInstance = (CommittedInstance<C1>, Witness<C1>);
|
||||
type IncomingInstance = (CommittedInstance<C1>, Witness<C1>);
|
||||
type MultiCommittedInstanceWithWitness = ();
|
||||
@@ -377,12 +398,12 @@ where
|
||||
(cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_rows)?;
|
||||
}
|
||||
|
||||
let prover_params = ProverParams::<C1, C2, CS1, CS2> {
|
||||
let prover_params = ProverParams::<C1, C2, CS1, CS2, H> {
|
||||
poseidon_config: prep_param.poseidon_config.clone(),
|
||||
cs_pp: cs_pp.clone(),
|
||||
cf_cs_pp: cf_cs_pp.clone(),
|
||||
};
|
||||
let verifier_params = VerifierParams::<C1, C2, CS1, CS2> {
|
||||
let verifier_params = VerifierParams::<C1, C2, CS1, CS2, H> {
|
||||
poseidon_config: prep_param.poseidon_config.clone(),
|
||||
r1cs,
|
||||
cf_r1cs,
|
||||
@@ -455,11 +476,26 @@ where
|
||||
/// Implements IVC.P of Nova+CycleFold
|
||||
fn prove_step(
|
||||
&mut self,
|
||||
_rng: impl RngCore,
|
||||
mut rng: impl RngCore,
|
||||
external_inputs: Vec<C1::ScalarField>,
|
||||
// Nova does not support multi-instances folding
|
||||
_other_instances: Option<Self::MultiCommittedInstanceWithWitness>,
|
||||
) -> Result<(), Error> {
|
||||
// ensure that commitments are blinding if user has specified so.
|
||||
if H && self.i >= C1::ScalarField::one() {
|
||||
let blinding_commitments = if self.i == C1::ScalarField::one() {
|
||||
// blinding values of the running instances are zero at the first iteration
|
||||
vec![self.w_i.rW, self.w_i.rE]
|
||||
} else {
|
||||
vec![self.w_i.rW, self.w_i.rE, self.W_i.rW, self.W_i.rE]
|
||||
};
|
||||
if blinding_commitments.contains(&C1::ScalarField::zero()) {
|
||||
return Err(Error::IncorrectBlinding(
|
||||
H,
|
||||
format!("{:?}", blinding_commitments),
|
||||
));
|
||||
}
|
||||
}
|
||||
// `sponge` is for digest computation.
|
||||
let sponge = PoseidonSponge::<C1::ScalarField>::new(&self.poseidon_config);
|
||||
// `transcript` is for challenge generation.
|
||||
@@ -517,9 +553,10 @@ where
|
||||
.ok_or(Error::OutOfBounds)?;
|
||||
|
||||
// fold Nova instances
|
||||
let (W_i1, U_i1): (Witness<C1>, CommittedInstance<C1>) = NIFS::<C1, CS1>::fold_instances(
|
||||
r_Fr, &self.W_i, &self.U_i, &self.w_i, &self.u_i, &T, cmT,
|
||||
)?;
|
||||
let (W_i1, U_i1): (Witness<C1>, CommittedInstance<C1>) =
|
||||
NIFS::<C1, CS1, H>::fold_instances(
|
||||
r_Fr, &self.W_i, &self.U_i, &self.w_i, &self.u_i, &T, cmT,
|
||||
)?;
|
||||
|
||||
// folded instance output (public input, x)
|
||||
// u_{i+1}.x[0] = H(i+1, z_0, z_{i+1}, U_{i+1})
|
||||
@@ -561,7 +598,7 @@ where
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
NIFS::<C1, CS1>::verify_folded_instance(r_Fr, &self.U_i, &self.u_i, &U_i1, &cmT)?;
|
||||
NIFS::<C1, CS1, H>::verify_folded_instance(r_Fr, &self.U_i, &self.u_i, &U_i1, &cmT)?;
|
||||
} else {
|
||||
// CycleFold part:
|
||||
// get the vector used as public inputs 'x' in the CycleFold circuit
|
||||
@@ -604,6 +641,7 @@ where
|
||||
self.cf_U_i.clone(), // CycleFold running instance
|
||||
cfW_u_i_x,
|
||||
cfW_circuit,
|
||||
&mut rng,
|
||||
)?;
|
||||
// fold [the output from folding self.cf_U_i + cfW_U] + cfE_U = folded_running_with_cfW + cfE
|
||||
let (_cfE_w_i, cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = self.fold_cyclefold_circuit(
|
||||
@@ -612,6 +650,7 @@ where
|
||||
cfW_U_i1.clone(),
|
||||
cfE_u_i_x,
|
||||
cfE_circuit,
|
||||
&mut rng,
|
||||
)?;
|
||||
|
||||
cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash);
|
||||
@@ -674,8 +713,8 @@ where
|
||||
// set values for next iteration
|
||||
self.i += C1::ScalarField::one();
|
||||
self.z_i = z_i1;
|
||||
self.w_i = Witness::<C1>::new(w_i1, self.r1cs.A.n_rows);
|
||||
self.u_i = self.w_i.commit::<CS1>(&self.cs_pp, x_i1)?;
|
||||
self.w_i = Witness::<C1>::new::<H>(w_i1, self.r1cs.A.n_rows, &mut rng);
|
||||
self.u_i = self.w_i.commit::<CS1, H>(&self.cs_pp, x_i1)?;
|
||||
self.W_i = W_i1;
|
||||
self.U_i = U_i1;
|
||||
|
||||
@@ -767,15 +806,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> Nova<C1, GC1, C2, GC2, FC, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
<C2 as Group>::ScalarField: Absorb,
|
||||
@@ -783,7 +822,7 @@ where
|
||||
{
|
||||
// computes T and cmT for the AugmentedFCircuit
|
||||
fn compute_cmT(&self) -> Result<(Vec<C1::ScalarField>, C1), Error> {
|
||||
NIFS::<C1, CS1>::compute_cmT(
|
||||
NIFS::<C1, CS1, H>::compute_cmT(
|
||||
&self.cs_pp,
|
||||
&self.r1cs,
|
||||
&self.w_i,
|
||||
@@ -794,15 +833,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> Nova<C1, GC1, C2, GC2, FC, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
@@ -820,6 +859,7 @@ where
|
||||
cf_U_i: CommittedInstance<C2>, // running instance
|
||||
cf_u_i_x: Vec<C2::ScalarField>,
|
||||
cf_circuit: CycleFoldCircuit<C1, GC1>,
|
||||
rng: &mut impl RngCore,
|
||||
) -> Result<
|
||||
(
|
||||
Witness<C2>,
|
||||
@@ -831,7 +871,7 @@ where
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2>(
|
||||
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2, H>(
|
||||
NOVA_CF_N_POINTS,
|
||||
transcript,
|
||||
self.cf_r1cs.clone(),
|
||||
@@ -841,6 +881,7 @@ where
|
||||
cf_U_i,
|
||||
cf_u_i_x,
|
||||
cf_circuit,
|
||||
rng,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -929,35 +970,60 @@ pub mod tests {
|
||||
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
|
||||
|
||||
// run the test using Pedersen commitments on both sides of the curve cycle
|
||||
test_ivc_opt::<Pedersen<Projective>, Pedersen<Projective2>>(
|
||||
test_ivc_opt::<Pedersen<Projective>, Pedersen<Projective2>, false>(
|
||||
poseidon_config.clone(),
|
||||
F_circuit,
|
||||
);
|
||||
test_ivc_opt::<Pedersen<Projective, true>, Pedersen<Projective2, true>, true>(
|
||||
poseidon_config.clone(),
|
||||
F_circuit,
|
||||
);
|
||||
|
||||
// run the test using KZG for the commitments on the main curve, and Pedersen for the
|
||||
// commitments on the secondary curve
|
||||
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>>(poseidon_config, F_circuit);
|
||||
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>, false>(poseidon_config, F_circuit);
|
||||
}
|
||||
|
||||
// test_ivc allowing to choose the CommitmentSchemes
|
||||
fn test_ivc_opt<CS1: CommitmentScheme<Projective>, CS2: CommitmentScheme<Projective2>>(
|
||||
fn test_ivc_opt<
|
||||
CS1: CommitmentScheme<Projective, H>,
|
||||
CS2: CommitmentScheme<Projective2, H>,
|
||||
const H: bool,
|
||||
>(
|
||||
poseidon_config: PoseidonConfig<Fr>,
|
||||
F_circuit: CubicFCircuit<Fr>,
|
||||
) {
|
||||
let mut rng = ark_std::test_rng();
|
||||
type N<CS1, CS2> = Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
||||
|
||||
let prep_param = PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2> {
|
||||
poseidon_config,
|
||||
F: F_circuit,
|
||||
cs_pp: None,
|
||||
cs_vp: None,
|
||||
cf_cs_pp: None,
|
||||
cf_cs_vp: None,
|
||||
};
|
||||
let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||
let prep_param =
|
||||
PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2, H> {
|
||||
poseidon_config,
|
||||
F: F_circuit,
|
||||
cs_pp: None,
|
||||
cs_vp: None,
|
||||
cf_cs_pp: None,
|
||||
cf_cs_vp: None,
|
||||
};
|
||||
let nova_params = Nova::<
|
||||
Projective,
|
||||
GVar,
|
||||
Projective2,
|
||||
GVar2,
|
||||
CubicFCircuit<Fr>,
|
||||
CS1,
|
||||
CS2,
|
||||
H,
|
||||
>::preprocess(&mut rng, &prep_param)
|
||||
.unwrap();
|
||||
|
||||
let z_0 = vec![Fr::from(3_u32)];
|
||||
let mut nova = N::init(&nova_params, F_circuit, z_0.clone()).unwrap();
|
||||
let mut nova =
|
||||
Nova::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2, H>::init(
|
||||
&nova_params,
|
||||
F_circuit,
|
||||
z_0.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let num_steps: usize = 3;
|
||||
for _ in 0..num_steps {
|
||||
@@ -966,7 +1032,7 @@ pub mod tests {
|
||||
assert_eq!(Fr::from(num_steps as u32), nova.i);
|
||||
|
||||
let (running_instance, incoming_instance, cyclefold_instance) = nova.instances();
|
||||
N::<CS1, CS2>::verify(
|
||||
Nova::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2, H>::verify(
|
||||
nova_params.1, // Nova's verifier params
|
||||
z_0,
|
||||
nova.z_i,
|
||||
|
||||
@@ -12,12 +12,13 @@ use crate::Error;
|
||||
|
||||
/// Implements the Non-Interactive Folding Scheme described in section 4 of
|
||||
/// [Nova](https://eprint.iacr.org/2021/370.pdf)
|
||||
pub struct NIFS<C: CurveGroup, CS: CommitmentScheme<C>> {
|
||||
/// `H` specifies whether the NIFS will use a blinding factor
|
||||
pub struct NIFS<C: CurveGroup, CS: CommitmentScheme<C, H>, const H: bool = false> {
|
||||
_c: PhantomData<C>,
|
||||
_cp: PhantomData<CS>,
|
||||
}
|
||||
|
||||
impl<C: CurveGroup, CS: CommitmentScheme<C>> NIFS<C, CS>
|
||||
impl<C: CurveGroup, CS: CommitmentScheme<C, H>, const H: bool> NIFS<C, CS, H>
|
||||
where
|
||||
<C as Group>::ScalarField: Absorb,
|
||||
{
|
||||
@@ -141,10 +142,10 @@ where
|
||||
) -> Result<(Witness<C>, CommittedInstance<C>), Error> {
|
||||
// fold witness
|
||||
// use r_T=0 since we don't need hiding property for cm(T)
|
||||
let w3 = NIFS::<C, CS>::fold_witness(r, w1, w2, T, C::ScalarField::zero())?;
|
||||
let w3 = NIFS::<C, CS, H>::fold_witness(r, w1, w2, T, C::ScalarField::zero())?;
|
||||
|
||||
// fold committed instances
|
||||
let ci3 = NIFS::<C, CS>::fold_committed_instance(r, ci1, ci2, &cmT);
|
||||
let ci3 = NIFS::<C, CS, H>::fold_committed_instance(r, ci1, ci2, &cmT);
|
||||
|
||||
Ok((w3, ci3))
|
||||
}
|
||||
@@ -158,7 +159,7 @@ where
|
||||
ci2: &CommittedInstance<C>,
|
||||
cmT: &C,
|
||||
) -> CommittedInstance<C> {
|
||||
NIFS::<C, CS>::fold_committed_instance(r, ci1, ci2, cmT)
|
||||
NIFS::<C, CS, H>::fold_committed_instance(r, ci1, ci2, cmT)
|
||||
}
|
||||
|
||||
/// Verify committed folded instance (ci) relations. Notice that this method does not open the
|
||||
@@ -206,7 +207,7 @@ pub mod tests {
|
||||
};
|
||||
use ark_ff::{BigInteger, PrimeField};
|
||||
use ark_pallas::{Fr, Projective};
|
||||
use ark_std::{ops::Mul, UniformRand};
|
||||
use ark_std::{ops::Mul, test_rng, UniformRand};
|
||||
|
||||
use crate::arith::r1cs::tests::{get_test_r1cs, get_test_z};
|
||||
use crate::commitment::pedersen::{Params as PedersenParams, Pedersen};
|
||||
@@ -241,18 +242,18 @@ pub mod tests {
|
||||
let (w1, x1) = r1cs.split_z(&z1);
|
||||
let (w2, x2) = r1cs.split_z(&z2);
|
||||
|
||||
let w1 = Witness::<C>::new(w1.clone(), r1cs.A.n_rows);
|
||||
let w2 = Witness::<C>::new(w2.clone(), r1cs.A.n_rows);
|
||||
let w1 = Witness::<C>::new::<false>(w1.clone(), r1cs.A.n_rows, test_rng());
|
||||
let w2 = Witness::<C>::new::<false>(w2.clone(), r1cs.A.n_rows, test_rng());
|
||||
|
||||
let mut rng = ark_std::test_rng();
|
||||
let (pedersen_params, _) = Pedersen::<C>::setup(&mut rng, r1cs.A.n_cols).unwrap();
|
||||
|
||||
// compute committed instances
|
||||
let ci1 = w1
|
||||
.commit::<Pedersen<C>>(&pedersen_params, x1.clone())
|
||||
.commit::<Pedersen<C>, false>(&pedersen_params, x1.clone())
|
||||
.unwrap();
|
||||
let ci2 = w2
|
||||
.commit::<Pedersen<C>>(&pedersen_params, x2.clone())
|
||||
.commit::<Pedersen<C>, false>(&pedersen_params, x2.clone())
|
||||
.unwrap();
|
||||
|
||||
// NIFS.P
|
||||
@@ -304,9 +305,9 @@ pub mod tests {
|
||||
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, r1cs.A.n_cols).unwrap();
|
||||
|
||||
// dummy instance, witness and public inputs zeroes
|
||||
let w_dummy = Witness::<Projective>::new(vec![Fr::zero(); w1.len()], r1cs.A.n_rows);
|
||||
let w_dummy = Witness::<Projective>::dummy(w1.len(), r1cs.A.n_rows);
|
||||
let mut u_dummy = w_dummy
|
||||
.commit::<Pedersen<Projective>>(&pedersen_params, vec![Fr::zero(); x1.len()])
|
||||
.commit::<Pedersen<Projective>, false>(&pedersen_params, vec![Fr::zero(); x1.len()])
|
||||
.unwrap();
|
||||
u_dummy.u = Fr::zero();
|
||||
|
||||
@@ -353,7 +354,7 @@ pub mod tests {
|
||||
// check that folded commitments from folded instance (ci) are equal to folding the
|
||||
// use folded rE, rW to commit w3
|
||||
let ci3_expected = w3
|
||||
.commit::<Pedersen<Projective>>(&pedersen_params, ci3.x.clone())
|
||||
.commit::<Pedersen<Projective>, false>(&pedersen_params, ci3.x.clone())
|
||||
.unwrap();
|
||||
assert_eq!(ci3_expected.cmE, ci3.cmE);
|
||||
assert_eq!(ci3_expected.cmW, ci3.cmW);
|
||||
@@ -417,9 +418,10 @@ pub mod tests {
|
||||
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, r1cs.A.n_cols).unwrap();
|
||||
|
||||
// prepare the running instance
|
||||
let mut running_instance_w = Witness::<Projective>::new(w.clone(), r1cs.A.n_rows);
|
||||
let mut running_instance_w =
|
||||
Witness::<Projective>::new::<false>(w.clone(), r1cs.A.n_rows, test_rng());
|
||||
let mut running_committed_instance = running_instance_w
|
||||
.commit::<Pedersen<Projective>>(&pedersen_params, x)
|
||||
.commit::<Pedersen<Projective>, false>(&pedersen_params, x)
|
||||
.unwrap();
|
||||
|
||||
r1cs.check_relaxed_instance_relation(&running_instance_w, &running_committed_instance)
|
||||
@@ -430,9 +432,10 @@ pub mod tests {
|
||||
// prepare the incoming instance
|
||||
let incoming_instance_z = get_test_z(i + 4);
|
||||
let (w, x) = r1cs.split_z(&incoming_instance_z);
|
||||
let incoming_instance_w = Witness::<Projective>::new(w.clone(), r1cs.A.n_rows);
|
||||
let incoming_instance_w =
|
||||
Witness::<Projective>::new::<false>(w.clone(), r1cs.A.n_rows, test_rng());
|
||||
let incoming_committed_instance = incoming_instance_w
|
||||
.commit::<Pedersen<Projective>>(&pedersen_params, x)
|
||||
.commit::<Pedersen<Projective>, false>(&pedersen_params, x)
|
||||
.unwrap();
|
||||
r1cs.check_relaxed_instance_relation(
|
||||
&incoming_instance_w,
|
||||
|
||||
@@ -21,13 +21,14 @@ use crate::{
|
||||
frontend::FCircuit,
|
||||
};
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> CanonicalSerialize for Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> CanonicalSerialize
|
||||
for Nova<C1, GC1, C2, GC2, FC, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
@@ -94,13 +95,13 @@ where
|
||||
|
||||
// Note that we can't derive or implement `CanonicalDeserialize` directly.
|
||||
// This is because `CurveVar` notably does not implement the `Sync` trait.
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> Nova<C1, GC1, C2, GC2, FC, CS1, CS2, H>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
FC: FCircuit<CF1<C1>, Params = ()>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
CS1: CommitmentScheme<C1, H>,
|
||||
CS2: CommitmentScheme<C2, H>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
@@ -117,7 +118,7 @@ where
|
||||
mut reader: R,
|
||||
compress: ark_serialize::Compress,
|
||||
validate: ark_serialize::Validate,
|
||||
prover_params: ProverParams<C1, C2, CS1, CS2>,
|
||||
prover_params: ProverParams<C1, C2, CS1, CS2, H>,
|
||||
poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||
) -> Result<Self, ark_serialize::SerializationError> {
|
||||
let pp_hash = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
|
||||
@@ -152,7 +153,6 @@ where
|
||||
cs2.finalize();
|
||||
let cs2 = cs2.into_inner().ok_or(SerializationError::InvalidData)?;
|
||||
let cf_r1cs = extract_r1cs::<C1::BaseField>(&cs2);
|
||||
|
||||
Ok(Nova {
|
||||
_gc1: PhantomData,
|
||||
_c2: PhantomData,
|
||||
@@ -207,6 +207,7 @@ pub mod tests {
|
||||
CubicFCircuit<Fr>,
|
||||
KZG<'static, Bn254>,
|
||||
Pedersen<Projective2>,
|
||||
false,
|
||||
>;
|
||||
let prep_param = PreprocessorParam::new(poseidon_config.clone(), F_circuit);
|
||||
let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||
@@ -242,6 +243,7 @@ pub mod tests {
|
||||
CubicFCircuit<Fr>,
|
||||
KZG<Bn254>,
|
||||
Pedersen<Projective2>,
|
||||
false,
|
||||
>::deserialize_nova(
|
||||
bytes.as_slice(),
|
||||
Compress::No,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use ark_crypto_primitives::sponge::Absorb;
|
||||
use ark_ec::{CurveGroup, Group};
|
||||
use ark_std::{One, Zero};
|
||||
use ark_std::One;
|
||||
|
||||
use super::{CommittedInstance, Witness};
|
||||
use crate::arith::{r1cs::R1CS, Arith};
|
||||
@@ -34,7 +34,7 @@ where
|
||||
{
|
||||
fn dummy_instance(&self) -> (Witness<C>, CommittedInstance<C>) {
|
||||
let w_len = self.A.n_cols - 1 - self.l;
|
||||
let w_dummy = Witness::<C>::new(vec![C::ScalarField::zero(); w_len], self.A.n_rows);
|
||||
let w_dummy = Witness::<C>::dummy(w_len, self.A.n_rows);
|
||||
let u_dummy = CommittedInstance::<C>::dummy(self.l);
|
||||
(w_dummy, u_dummy)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user