From afd7403336fdf6625658108256f4b4163da197c9 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Thu, 18 May 2023 10:45:08 -0700 Subject: [PATCH] Fix cross-curve check and then eliminate an unnecessary instance on the primary curve (#167) * add a cross-curve consistency check * eliminate the unused instance in RecursiveSNARK --- src/lib.rs | 103 +++++++++++++++++------------------------------------ 1 file changed, 33 insertions(+), 70 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ac0a548..8ee6854 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,8 +175,6 @@ where { r_W_primary: RelaxedR1CSWitness, r_U_primary: RelaxedR1CSInstance, - l_w_primary: R1CSWitness, - l_u_primary: R1CSInstance, r_W_secondary: RelaxedR1CSWitness, r_U_secondary: RelaxedR1CSInstance, l_w_secondary: R1CSWitness, @@ -285,8 +283,6 @@ where Ok(Self { r_W_primary, r_U_primary, - l_w_primary, - l_u_primary, r_W_secondary, r_U_secondary, l_w_secondary, @@ -353,7 +349,7 @@ where z0_secondary, Some(r_snark.zi_secondary.clone()), Some(r_snark.r_U_primary.clone()), - Some(l_u_primary.clone()), + Some(l_u_primary), Some(Commitment::::decompress(&nifs_primary.comm_T)?), ); @@ -376,8 +372,6 @@ where Ok(Self { r_W_primary, r_U_primary, - l_w_primary, - l_u_primary, r_W_secondary, r_U_secondary, l_w_secondary, @@ -411,8 +405,7 @@ where } // check if the (relaxed) R1CS instances have two public outputs - if self.l_u_primary.X.len() != 2 - || self.l_u_secondary.X.len() != 2 + if self.l_u_secondary.X.len() != 2 || self.r_U_primary.X.len() != 2 || self.r_U_secondary.X.len() != 2 { @@ -455,28 +448,17 @@ where ) }; - if hash_primary != scalar_as_base::(self.l_u_primary.X[1]) + if hash_primary != self.l_u_secondary.X[0] || hash_secondary != scalar_as_base::(self.l_u_secondary.X[1]) { return Err(NovaError::ProofVerifyError); } // check the satisfiability of the provided instances - let ((res_r_primary, res_l_primary), (res_r_secondary, res_l_secondary)) = rayon::join( + let (res_r_primary, (res_r_secondary, res_l_secondary)) = rayon::join( || { - rayon::join( - || { - pp.r1cs_shape_primary.is_sat_relaxed( - &pp.ck_primary, - &self.r_U_primary, - &self.r_W_primary, - ) - }, - || { - pp.r1cs_shape_primary - .is_sat(&pp.ck_primary, &self.l_u_primary, &self.l_w_primary) - }, - ) + pp.r1cs_shape_primary + .is_sat_relaxed(&pp.ck_primary, &self.r_U_primary, &self.r_W_primary) }, || { rayon::join( @@ -500,7 +482,6 @@ where // check the returned res objects res_r_primary?; - res_l_primary?; res_r_secondary?; res_l_secondary?; @@ -562,9 +543,7 @@ where S2: RelaxedR1CSSNARKTrait, { r_U_primary: RelaxedR1CSInstance, - l_u_primary: R1CSInstance, - nifs_primary: NIFS, - f_W_snark_primary: S1, + r_W_snark_primary: S1, r_U_secondary: RelaxedR1CSInstance, l_u_secondary: R1CSInstance, @@ -628,41 +607,30 @@ where pk: &ProverKey, recursive_snark: &RecursiveSNARK, ) -> Result { - let (res_primary, res_secondary) = rayon::join( - // fold the primary circuit's instance + // fold the secondary circuit's instance + let res_secondary = NIFS::prove( + &pp.ck_secondary, + &pp.ro_consts_secondary, + &scalar_as_base::(pp.digest), + &pp.r1cs_shape_secondary, + &recursive_snark.r_U_secondary, + &recursive_snark.r_W_secondary, + &recursive_snark.l_u_secondary, + &recursive_snark.l_w_secondary, + ); + + let (nifs_secondary, (f_U_secondary, f_W_secondary)) = res_secondary?; + + // create SNARKs proving the knowledge of f_W_primary and f_W_secondary + let (r_W_snark_primary, f_W_snark_secondary) = rayon::join( || { - NIFS::prove( + S1::prove( &pp.ck_primary, - &pp.ro_consts_primary, - &pp.digest, - &pp.r1cs_shape_primary, + &pk.pk_primary, &recursive_snark.r_U_primary, &recursive_snark.r_W_primary, - &recursive_snark.l_u_primary, - &recursive_snark.l_w_primary, ) }, - || { - // fold the secondary circuit's instance - NIFS::prove( - &pp.ck_secondary, - &pp.ro_consts_secondary, - &scalar_as_base::(pp.digest), - &pp.r1cs_shape_secondary, - &recursive_snark.r_U_secondary, - &recursive_snark.r_W_secondary, - &recursive_snark.l_u_secondary, - &recursive_snark.l_w_secondary, - ) - }, - ); - - let (nifs_primary, (f_U_primary, f_W_primary)) = res_primary?; - let (nifs_secondary, (f_U_secondary, f_W_secondary)) = res_secondary?; - - // create SNARKs proving the knowledge of f_W_primary and f_W_secondary - let (f_W_snark_primary, f_W_snark_secondary) = rayon::join( - || S1::prove(&pp.ck_primary, &pk.pk_primary, &f_U_primary, &f_W_primary), || { S2::prove( &pp.ck_secondary, @@ -675,9 +643,7 @@ where Ok(Self { r_U_primary: recursive_snark.r_U_primary.clone(), - l_u_primary: recursive_snark.l_u_primary.clone(), - nifs_primary, - f_W_snark_primary: f_W_snark_primary?, + r_W_snark_primary: r_W_snark_primary?, r_U_secondary: recursive_snark.r_U_secondary.clone(), l_u_secondary: recursive_snark.l_u_secondary.clone(), @@ -706,8 +672,7 @@ where } // check if the (relaxed) R1CS instances have two public outputs - if self.l_u_primary.X.len() != 2 - || self.l_u_secondary.X.len() != 2 + if self.l_u_secondary.X.len() != 2 || self.r_U_primary.X.len() != 2 || self.r_U_secondary.X.len() != 2 { @@ -750,19 +715,13 @@ where ) }; - if hash_primary != scalar_as_base::(self.l_u_primary.X[1]) + if hash_primary != self.l_u_secondary.X[0] || hash_secondary != scalar_as_base::(self.l_u_secondary.X[1]) { return Err(NovaError::ProofVerifyError); } // fold the running instance and last instance to get a folded instance - let f_U_primary = self.nifs_primary.verify( - &vk.ro_consts_primary, - &vk.digest, - &self.r_U_primary, - &self.l_u_primary, - )?; let f_U_secondary = self.nifs_secondary.verify( &vk.ro_consts_secondary, &scalar_as_base::(vk.digest), @@ -772,7 +731,11 @@ where // check the satisfiability of the folded instances using SNARKs proving the knowledge of their satisfying witnesses let (res_primary, res_secondary) = rayon::join( - || self.f_W_snark_primary.verify(&vk.vk_primary, &f_U_primary), + || { + self + .r_W_snark_primary + .verify(&vk.vk_primary, &self.r_U_primary) + }, || { self .f_W_snark_secondary