Skip to content

Commit

Permalink
R1CS: Allow non-static lifetimes for second-phase closures.
Browse files Browse the repository at this point in the history
This adds a general lifetime for the second-phase constraints on
RandomizeableConstraintSystem, which should cover the lifetime of each
closure given to specify_randomized_constraints().  The latter can
receive shorter lifetimes.
  • Loading branch information
rubdos committed May 14, 2020
1 parent ec19cb3 commit 8728213
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 29 deletions.
11 changes: 7 additions & 4 deletions src/r1cs/constraint_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -104,9 +104,12 @@ pub trait RandomizableConstraintSystem: ConstraintSystem {
/// // ...
/// })
/// ```
fn specify_randomized_constraints<F>(&mut self, callback: F) -> Result<(), R1CSError>
fn specify_randomized_constraints<'a: 'constraints, F>(
&mut self,
callback: F,
) -> Result<(), R1CSError>
where
F: 'static + FnOnce(&mut Self::RandomizedCS) -> Result<(), R1CSError>;
F: 'a + FnOnce(&mut Self::RandomizedCS) -> Result<(), R1CSError>;
}

/// Represents a constraint system in the second phase:
Expand Down
31 changes: 19 additions & 12 deletions src/r1cs/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Transcript>> {
pub struct Prover<'g, 'c, T: BorrowMut<Transcript>> {
transcript: T,
pc_gens: &'g PedersenGens,
/// The constraints accumulated so far.
Expand All @@ -38,7 +38,7 @@ pub struct Prover<'g, T: BorrowMut<Transcript>> {
/// This list holds closures that will be called in the second phase of the protocol,
/// when non-randomized variables are committed.
deferred_constraints:
Vec<Box<dyn FnOnce(&mut RandomizingProver<'g, T>) -> Result<(), R1CSError>>>,
Vec<Box<dyn 'c + FnOnce(&mut RandomizingProver<'g, 'c, T>) -> Result<(), R1CSError>>>,

/// Index of a pending multiplier that's not fully assigned yet.
pending_multiplier: Option<usize>,
Expand Down Expand Up @@ -66,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<Transcript>> {
prover: Prover<'g, T>,
pub struct RandomizingProver<'g, 'c, T: BorrowMut<Transcript>> {
prover: Prover<'g, 'c, T>,
}

/// Overwrite secrets with null bytes when they go out of scope.
Expand All @@ -94,7 +94,7 @@ impl Drop for Secrets {
}
}

impl<'g, T: BorrowMut<Transcript>> ConstraintSystem for Prover<'g, T> {
impl<'g, 'c, T: BorrowMut<Transcript>> ConstraintSystem for Prover<'g, 'c, T> {
fn transcript(&mut self) -> &mut Transcript {
self.transcript.borrow_mut()
}
Expand Down Expand Up @@ -178,19 +178,26 @@ impl<'g, T: BorrowMut<Transcript>> ConstraintSystem for Prover<'g, T> {
}
}

impl<'g, T: BorrowMut<Transcript>> RandomizableConstraintSystem for Prover<'g, T> {
type RandomizedCS = RandomizingProver<'g, T>;
impl<'g, 'constraints, T: BorrowMut<Transcript> + 'constraints>
RandomizableConstraintSystem<'constraints> for Prover<'g, 'constraints, T>
where
'g: 'constraints,
{
type RandomizedCS = RandomizingProver<'g, 'constraints, T>;

fn specify_randomized_constraints<F>(&mut self, callback: F) -> Result<(), R1CSError>
fn specify_randomized_constraints<'a: 'constraints, F>(
&mut self,
callback: F,
) -> Result<(), R1CSError>
where
F: 'static + FnOnce(&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<Transcript>> ConstraintSystem for RandomizingProver<'g, T> {
impl<'g, 'c, T: BorrowMut<Transcript>> ConstraintSystem for RandomizingProver<'g, 'c, T> {
fn transcript(&mut self) -> &mut Transcript {
self.prover.transcript.borrow_mut()
}
Expand Down Expand Up @@ -223,13 +230,13 @@ impl<'g, T: BorrowMut<Transcript>> ConstraintSystem for RandomizingProver<'g, T>
}
}

impl<'g, T: BorrowMut<Transcript>> RandomizedConstraintSystem for RandomizingProver<'g, T> {
impl<'g, 'c, T: BorrowMut<Transcript>> 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<Transcript>> Prover<'g, T> {
impl<'g, 'c, T: BorrowMut<Transcript>> Prover<'g, 'c, T> {
/// Construct an empty constraint system with specified external
/// input variables.
///
Expand Down
29 changes: 17 additions & 12 deletions src/r1cs/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: BorrowMut<Transcript>> {
pub struct Verifier<'c, T: BorrowMut<Transcript>> {
transcript: T,
constraints: Vec<LinearCombination>,

Expand All @@ -44,7 +44,7 @@ pub struct Verifier<T: BorrowMut<Transcript>> {
/// After that, the option will flip to None and additional calls to `randomize_constraints`
/// will invoke closures immediately.
deferred_constraints:
Vec<Box<dyn FnOnce(&mut RandomizingVerifier<T>) -> Result<(), R1CSError>>>,
Vec<Box<dyn 'c + FnOnce(&mut RandomizingVerifier<'c, T>) -> Result<(), R1CSError>>>,

/// Index of a pending multiplier that's not fully assigned yet.
pending_multiplier: Option<usize>,
Expand All @@ -57,11 +57,11 @@ pub struct Verifier<T: BorrowMut<Transcript>> {
/// 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<T: BorrowMut<Transcript>> {
verifier: Verifier<T>,
pub struct RandomizingVerifier<'c, T: BorrowMut<Transcript>> {
verifier: Verifier<'c, T>,
}

impl<T: BorrowMut<Transcript>> ConstraintSystem for Verifier<T> {
impl<'c, T: BorrowMut<Transcript>> ConstraintSystem for Verifier<'c, T> {
fn transcript(&mut self) -> &mut Transcript {
self.transcript.borrow_mut()
}
Expand Down Expand Up @@ -130,19 +130,24 @@ impl<T: BorrowMut<Transcript>> ConstraintSystem for Verifier<T> {
}
}

impl<T: BorrowMut<Transcript>> RandomizableConstraintSystem for Verifier<T> {
type RandomizedCS = RandomizingVerifier<T>;
impl<'constraints, T: BorrowMut<Transcript> + 'constraints>
RandomizableConstraintSystem<'constraints> for Verifier<'constraints, T>
{
type RandomizedCS = RandomizingVerifier<'constraints, T>;

fn specify_randomized_constraints<F>(&mut self, callback: F) -> Result<(), R1CSError>
fn specify_randomized_constraints<'a: 'constraints, F>(
&mut self,
callback: F,
) -> Result<(), R1CSError>
where
F: 'static + FnOnce(&mut Self::RandomizedCS) -> Result<(), R1CSError>,
F: 'a + FnOnce(&mut Self::RandomizedCS) -> Result<(), R1CSError>,
{
self.deferred_constraints.push(Box::new(callback));
Ok(())
}
}

impl<T: BorrowMut<Transcript>> ConstraintSystem for RandomizingVerifier<T> {
impl<'c, T: BorrowMut<Transcript>> ConstraintSystem for RandomizingVerifier<'c, T> {
fn transcript(&mut self) -> &mut Transcript {
self.verifier.transcript.borrow_mut()
}
Expand Down Expand Up @@ -175,7 +180,7 @@ impl<T: BorrowMut<Transcript>> ConstraintSystem for RandomizingVerifier<T> {
}
}

impl<T: BorrowMut<Transcript>> RandomizedConstraintSystem for RandomizingVerifier<T> {
impl<'c, T: BorrowMut<Transcript>> RandomizedConstraintSystem for RandomizingVerifier<'c, T> {
fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
self.verifier
.transcript
Expand All @@ -184,7 +189,7 @@ impl<T: BorrowMut<Transcript>> RandomizedConstraintSystem for RandomizingVerifie
}
}

impl<T: BorrowMut<Transcript>> Verifier<T> {
impl<'c, T: BorrowMut<Transcript>> Verifier<'c, T> {
/// Construct an empty constraint system with specified external
/// input variables.
///
Expand Down
37 changes: 36 additions & 1 deletion tests/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rand::thread_rng;
struct ShuffleProof(R1CSProof);

impl ShuffleProof {
fn gadget<CS: RandomizableConstraintSystem>(
fn gadget<'c, CS: RandomizableConstraintSystem<'c>>(
cs: &mut CS,
x: Vec<Variable>,
y: Vec<Variable>,
Expand Down Expand Up @@ -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();
}

0 comments on commit 8728213

Please sign in to comment.