diff --git a/.github/workflows/testudo.yml b/.github/workflows/testudo.yml index 3d2063b..781bd98 100644 --- a/.github/workflows/testudo.yml +++ b/.github/workflows/testudo.yml @@ -21,8 +21,8 @@ jobs: run: rustup default nightly - name: Install rustfmt Components run: rustup component add rustfmt - - name: Install clippy - run: rustup component add clippy + # - name: Install clippy + # run: rustup component add clippy - name: Build run: cargo build --verbose - name: Run tests @@ -32,6 +32,6 @@ jobs: - name: Check Rustfmt Code Style run: cargo fmt --all -- --check # cargo clippy uses cargo check which returns an error when asm is emitted - # we want to emit asm for ff operations so we avoid using clippy for now + # we want to emit asm for ark-ff operations so we avoid using clippy for # now # - name: Check clippy warnings # run: cargo clippy --all-targets --all-features diff --git a/src/constraints.rs b/src/constraints.rs index 85d1921..edd5453 100644 --- a/src/constraints.rs +++ b/src/constraints.rs @@ -255,6 +255,7 @@ pub struct R1CSVerificationCircuit { pub sc_phase2: SumcheckVerificationCircuit, // The point on which the polynomial was evaluated by the prover. pub claimed_ry: Vec, + pub claimed_transcript_sat_state: Scalar, } impl R1CSVerificationCircuit { @@ -276,6 +277,7 @@ impl R1CSVerificationCircuit { polys: config.polys_sc2.clone(), }, claimed_ry: config.ry.clone(), + claimed_transcript_sat_state: config.transcript_sat_state, } } } @@ -386,13 +388,21 @@ impl ConstraintSynthesizer for R1CSVerificationCircuit { let eval_A_r_var = FpVar::::new_witness(cs.clone(), || Ok(eval_A_r))?; let eval_B_r_var = FpVar::::new_witness(cs.clone(), || Ok(eval_B_r))?; - let eval_C_r_var = FpVar::::new_witness(cs, || Ok(eval_C_r))?; + let eval_C_r_var = FpVar::::new_witness(cs.clone(), || Ok(eval_C_r))?; let scalar_var = &r_A_var * &eval_A_r_var + &r_B_var * &eval_B_r_var + &r_C_var * &eval_C_r_var; let expected_claim_post_phase2_var = eval_Z_at_ry_var * scalar_var; claim_post_phase2_var.enforce_equal(&expected_claim_post_phase2_var)?; + let expected_transcript_state_var = transcript_var.challenge()?; + let claimed_transcript_state_var = + FpVar::::new_input(cs, || Ok(self.claimed_transcript_sat_state))?; + + // Ensure that the prover and verifier transcipt views are consistent at + // the end of the satisfiability proof. + expected_transcript_state_var.enforce_equal(&claimed_transcript_state_var)?; + Ok(()) } } @@ -411,6 +421,7 @@ pub struct VerifierConfig { pub polys_sc1: Vec, pub polys_sc2: Vec, pub ry: Vec, + pub transcript_sat_state: Scalar, } #[derive(Clone)] pub struct VerifierCircuit { @@ -420,6 +431,7 @@ pub struct VerifierCircuit { pub eval_vars_at_ry: Fr, pub claims_phase2: (Fr, Fr, Fr, Fr), pub ry: Vec, + pub transcript_sat_state: Scalar, } impl VerifierCircuit { @@ -438,6 +450,7 @@ impl VerifierCircuit { eval_vars_at_ry: config.eval_vars_at_ry, claims_phase2: config.claims_phase2, ry: config.ry.clone(), + transcript_sat_state: config.transcript_sat_state, }) } } @@ -449,7 +462,8 @@ impl ConstraintSynthesizer for VerifierCircuit { let mut pubs = vec![]; pubs.extend(self.ry); pubs.extend(vec![v_A, v_B, v_C, v_AB]); - pubs.extend(vec![self.eval_vars_at_ry]); + pubs.extend(vec![self.eval_vars_at_ry, self.transcript_sat_state]); + let bits = pubs .iter() .map(|c| { diff --git a/src/lib.rs b/src/lib.rs index 9e5286f..af4d4ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ mod constraints; pub mod poseidon_transcript; use ark_ff::Field; +use ark_relations::r1cs; use ark_serialize::*; use ark_std::Zero; use core::cmp::max; @@ -400,6 +401,13 @@ impl SNARK { (proof, rx, ry) }; + // We need to reset the transcript state before starting the evaluation + // proof and share this state with the verifier because, on the verifier's + // side all the previous updates are done on the transcript + // circuit variable and the transcript outside the circuit will be + // inconsistent wrt to the prover's. + transcript.new_from_state(&r1cs_sat_proof.transcript_sat_state); + // We send evaluations of A, B, C at r = (rx, ry) as claims // to enable the verifier complete the first sum-check let timer_eval = Timer::new("eval_sparse_polys"); @@ -466,24 +474,27 @@ impl SNARK { )?; timer_sat_proof.stop(); - // let timer_eval_proof = Timer::new("verify_eval_proof"); + let timer_eval_proof = Timer::new("verify_eval_proof"); + // Reset the transcript using the state sent by the prover. + // TODO: find a way to retrieve this state from the circuit. Currently + // the API for generating constraints doesn't support returning values + // computed inside the circuit. + transcript.new_from_state(&self.r1cs_sat_proof.transcript_sat_state); let (Ar, Br, Cr) = &self.inst_evals; transcript.append_scalar(&Ar); transcript.append_scalar(&Br); transcript.append_scalar(&Cr); - // TODO: debug this - // https://github.com/maramihali/Spartan/issues/6 - // self.r1cs_eval_proof.verify( - // &comm.comm, - // &self.rx, - // &self.ry, - // &self.inst_evals, - // &gens.gens_r1cs_eval, - // transcript, - // )?; - // timer_eval_proof.stop(); + self.r1cs_eval_proof.verify( + &comm.comm, + &self.rx, + &self.ry, + &self.inst_evals, + &gens.gens_r1cs_eval, + transcript, + )?; + timer_eval_proof.stop(); timer_verify.stop(); Ok(res) } diff --git a/src/r1csproof.rs b/src/r1csproof.rs index 6282550..5d9b139 100644 --- a/src/r1csproof.rs +++ b/src/r1csproof.rs @@ -40,6 +40,8 @@ pub struct R1CSProof { proof_eval_vars_at_ry: Proof, rx: Vec, ry: Vec, + // The transcript state after the satisfiability proof was computed. + pub transcript_sat_state: Scalar, } #[derive(Clone)] pub struct R1CSSumcheckGens { @@ -245,6 +247,8 @@ impl R1CSProof { timer_prove.stop(); + let c = transcript.challenge_scalar(); + ( R1CSProof { comm, @@ -255,6 +259,7 @@ impl R1CSProof { proof_eval_vars_at_ry, rx: rx.clone(), ry: ry.clone(), + transcript_sat_state: c, }, rx, ry, @@ -300,6 +305,7 @@ impl R1CSProof { input_as_sparse_poly, // rx: self.rx.clone(), ry: self.ry.clone(), + transcript_sat_state: self.transcript_sat_state, }; let mut rng = ark_std::test_rng(); @@ -389,6 +395,7 @@ impl R1CSProof { input_as_sparse_poly, // rx: self.rx.clone(), ry: self.ry.clone(), + transcript_sat_state: self.transcript_sat_state, }; let mut rng = ark_std::test_rng();