diff --git a/src/r1cs/constraint_system.rs b/src/r1cs/constraint_system.rs index cf327f26..d6f07b99 100644 --- a/src/r1cs/constraint_system.rs +++ b/src/r1cs/constraint_system.rs @@ -81,9 +81,9 @@ pub trait ConstraintSystem { /// while gadgets that need randomization should use trait bound `CS: RandomizedConstraintSystem`. /// Gadgets generally _should not_ use this trait as a bound on the CS argument: it should be used /// by the higher-order protocol that composes gadgets together. -pub trait RandomizableConstraintSystem: ConstraintSystem { +pub trait RandomizableConstraintSystem<'constraints>: ConstraintSystem { /// Represents a concrete type for the CS in a randomization phase. - type RandomizedCS: RandomizedConstraintSystem; + type RandomizedCS: RandomizedConstraintSystem + 'constraints; /// Specify additional variables and constraints randomized using a challenge scalar /// bound to the assignments of the non-randomized variables. @@ -104,9 +104,12 @@ pub trait RandomizableConstraintSystem: ConstraintSystem { /// // ... /// }) /// ``` - fn specify_randomized_constraints(&mut self, callback: F) -> Result<(), R1CSError> + fn specify_randomized_constraints<'a: 'constraints, F>( + &mut self, + callback: F, + ) -> Result<(), R1CSError> where - F: 'static + Fn(&mut Self::RandomizedCS) -> Result<(), R1CSError>; + F: 'a + FnOnce(&mut Self::RandomizedCS) -> Result<(), R1CSError>; } /// Represents a constraint system in the second phase: diff --git a/src/r1cs/prover.rs b/src/r1cs/prover.rs index 75c62d1f..1e4d7bd4 100644 --- a/src/r1cs/prover.rs +++ b/src/r1cs/prover.rs @@ -27,7 +27,7 @@ use crate::transcript::TranscriptProtocol; /// When all constraints are added, the proving code calls `prove` /// which consumes the `Prover` instance, samples random challenges /// that instantiate the randomized constraints, and creates a complete proof. -pub struct Prover<'g, T: BorrowMut> { +pub struct Prover<'g, 'c, T: BorrowMut> { transcript: T, pc_gens: &'g PedersenGens, /// The constraints accumulated so far. @@ -37,7 +37,8 @@ pub struct Prover<'g, T: BorrowMut> { /// This list holds closures that will be called in the second phase of the protocol, /// when non-randomized variables are committed. - deferred_constraints: Vec) -> Result<(), R1CSError>>>, + deferred_constraints: + Vec) -> Result<(), R1CSError>>>, /// Index of a pending multiplier that's not fully assigned yet. pending_multiplier: Option, @@ -65,8 +66,8 @@ struct Secrets { /// monomorphize the closures for the proving and verifying code. /// However, this type cannot be instantiated by the user and therefore can only be used within /// the callback provided to `specify_randomized_constraints`. -pub struct RandomizingProver<'g, T: BorrowMut> { - prover: Prover<'g, T>, +pub struct RandomizingProver<'g, 'c, T: BorrowMut> { + prover: Prover<'g, 'c, T>, } /// Overwrite secrets with null bytes when they go out of scope. @@ -93,7 +94,7 @@ impl Drop for Secrets { } } -impl<'g, T: BorrowMut> ConstraintSystem for Prover<'g, T> { +impl<'g, 'c, T: BorrowMut> ConstraintSystem for Prover<'g, 'c, T> { fn transcript(&mut self) -> &mut Transcript { self.transcript.borrow_mut() } @@ -177,19 +178,26 @@ impl<'g, T: BorrowMut> ConstraintSystem for Prover<'g, T> { } } -impl<'g, T: BorrowMut> RandomizableConstraintSystem for Prover<'g, T> { - type RandomizedCS = RandomizingProver<'g, T>; +impl<'g, 'constraints, T: BorrowMut + 'constraints> + RandomizableConstraintSystem<'constraints> for Prover<'g, 'constraints, T> +where + 'g: 'constraints, +{ + type RandomizedCS = RandomizingProver<'g, 'constraints, T>; - fn specify_randomized_constraints(&mut self, callback: F) -> Result<(), R1CSError> + fn specify_randomized_constraints<'a: 'constraints, F>( + &mut self, + callback: F, + ) -> Result<(), R1CSError> where - F: 'static + Fn(&mut Self::RandomizedCS) -> Result<(), R1CSError>, + F: 'a + FnOnce(&mut Self::RandomizedCS) -> Result<(), R1CSError>, { self.deferred_constraints.push(Box::new(callback)); Ok(()) } } -impl<'g, T: BorrowMut> ConstraintSystem for RandomizingProver<'g, T> { +impl<'g, 'c, T: BorrowMut> ConstraintSystem for RandomizingProver<'g, 'c, T> { fn transcript(&mut self) -> &mut Transcript { self.prover.transcript.borrow_mut() } @@ -222,13 +230,13 @@ impl<'g, T: BorrowMut> ConstraintSystem for RandomizingProver<'g, T> } } -impl<'g, T: BorrowMut> RandomizedConstraintSystem for RandomizingProver<'g, T> { +impl<'g, 'c, T: BorrowMut> RandomizedConstraintSystem for RandomizingProver<'g, 'c, T> { fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar { self.prover.transcript.borrow_mut().challenge_scalar(label) } } -impl<'g, T: BorrowMut> Prover<'g, T> { +impl<'g, 'c, T: BorrowMut> Prover<'g, 'c, T> { /// Construct an empty constraint system with specified external /// input variables. /// diff --git a/src/r1cs/verifier.rs b/src/r1cs/verifier.rs index cddbd425..6cc43f80 100644 --- a/src/r1cs/verifier.rs +++ b/src/r1cs/verifier.rs @@ -25,7 +25,7 @@ use crate::transcript::TranscriptProtocol; /// When all constraints are added, the verifying code calls `verify` /// which consumes the `Verifier` instance, samples random challenges /// that instantiate the randomized constraints, and verifies the proof. -pub struct Verifier> { +pub struct Verifier<'c, T: BorrowMut> { transcript: T, constraints: Vec, @@ -43,7 +43,8 @@ pub struct Verifier> { /// when non-randomized variables are committed. /// After that, the option will flip to None and additional calls to `randomize_constraints` /// will invoke closures immediately. - deferred_constraints: Vec) -> Result<(), R1CSError>>>, + deferred_constraints: + Vec) -> Result<(), R1CSError>>>, /// Index of a pending multiplier that's not fully assigned yet. pending_multiplier: Option, @@ -56,11 +57,11 @@ pub struct Verifier> { /// monomorphize the closures for the proving and verifying code. /// However, this type cannot be instantiated by the user and therefore can only be used within /// the callback provided to `specify_randomized_constraints`. -pub struct RandomizingVerifier> { - verifier: Verifier, +pub struct RandomizingVerifier<'c, T: BorrowMut> { + verifier: Verifier<'c, T>, } -impl> ConstraintSystem for Verifier { +impl<'c, T: BorrowMut> ConstraintSystem for Verifier<'c, T> { fn transcript(&mut self) -> &mut Transcript { self.transcript.borrow_mut() } @@ -129,19 +130,24 @@ impl> ConstraintSystem for Verifier { } } -impl> RandomizableConstraintSystem for Verifier { - type RandomizedCS = RandomizingVerifier; +impl<'constraints, T: BorrowMut + 'constraints> + RandomizableConstraintSystem<'constraints> for Verifier<'constraints, T> +{ + type RandomizedCS = RandomizingVerifier<'constraints, T>; - fn specify_randomized_constraints(&mut self, callback: F) -> Result<(), R1CSError> + fn specify_randomized_constraints<'a: 'constraints, F>( + &mut self, + callback: F, + ) -> Result<(), R1CSError> where - F: 'static + Fn(&mut Self::RandomizedCS) -> Result<(), R1CSError>, + F: 'a + FnOnce(&mut Self::RandomizedCS) -> Result<(), R1CSError>, { self.deferred_constraints.push(Box::new(callback)); Ok(()) } } -impl> ConstraintSystem for RandomizingVerifier { +impl<'c, T: BorrowMut> ConstraintSystem for RandomizingVerifier<'c, T> { fn transcript(&mut self) -> &mut Transcript { self.verifier.transcript.borrow_mut() } @@ -174,7 +180,7 @@ impl> ConstraintSystem for RandomizingVerifier { } } -impl> RandomizedConstraintSystem for RandomizingVerifier { +impl<'c, T: BorrowMut> RandomizedConstraintSystem for RandomizingVerifier<'c, T> { fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar { self.verifier .transcript @@ -183,7 +189,7 @@ impl> RandomizedConstraintSystem for RandomizingVerifie } } -impl> Verifier { +impl<'c, T: BorrowMut> Verifier<'c, T> { /// Construct an empty constraint system with specified external /// input variables. /// diff --git a/tests/r1cs.rs b/tests/r1cs.rs index d34775a0..023c85b9 100644 --- a/tests/r1cs.rs +++ b/tests/r1cs.rs @@ -19,7 +19,7 @@ use rand::thread_rng; struct ShuffleProof(R1CSProof); impl ShuffleProof { - fn gadget( + fn gadget<'c, CS: RandomizableConstraintSystem<'c>>( cs: &mut CS, x: Vec, y: Vec, @@ -452,3 +452,38 @@ fn range_proof_helper(v_val: u64, n: usize) -> Result<(), R1CSError> { // Verifier verifies proof verifier.verify(&proof, &pc_gens, &bp_gens) } + +#[test] +fn non_static_lifetimes() { + // Common + let pc_gens = PedersenGens::default(); + let bp_gens = BulletproofGens::new(128, 1); + + let a = 1; + let a: &u32 = &a; + + let proof = { + let mut prover_transcript = Transcript::new(b"NonStaticRandomClosuresTest"); + let mut prover = Prover::new(&pc_gens, &mut prover_transcript); + + prover + .specify_randomized_constraints(|rcs| { + rcs.constrain((Scalar::from(a.clone()) - Scalar::one()).into()); + Ok(()) + }) + .unwrap(); + + let proof = prover.prove(&bp_gens).unwrap(); + proof + }; + + let mut verifier_transcript = Transcript::new(b"NonStaticRandomClosuresTest"); + let mut verifier = Verifier::new(&mut verifier_transcript); + verifier + .specify_randomized_constraints(|rcs| { + rcs.constrain((Scalar::from(a.clone()) - Scalar::one()).into()); + Ok(()) + }) + .unwrap(); + verifier.verify(&proof, &pc_gens, &bp_gens).unwrap(); +}