Skip to content

Commit

Permalink
refactor: Refactor proof handling for ownership and borrowing (#1214)
Browse files Browse the repository at this point in the history
* refactor: Refactor proof handling for ownership and borrowing

On a long enough timeline, we'll want to generate compressed proofs without dropping the associated `RecursiveProof`. This is for the purpose of re-starting the proof using the prior
`RecursiveProof`, which at the moment can only be obtained through cloning prior to compression.

The current approach witnesses that compression only requires a reference to the current proof, and returns a `Cow`: the only situation in which this would result in a clone is if:
- we create a `CompressedProof`,
- we call `compress()` on it,
- we further perform a modificaiton of that `CompressedProof` that requires an owned value..

In detail:
- Updated `compress` function across various files to take `&self` instead of `self`, avoiding the drop of the `RecursiveProof`;
- Adjusted dependencies in chain-server's `Cargo.toml` to use workspace versions, streamlining dependency management and increasing project consistency.

* chore: clippy

* chore: update pointer to arecibo
  • Loading branch information
huitseeker authored Mar 19, 2024
1 parent 4266b15 commit 0d2ae13
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 35 deletions.
16 changes: 8 additions & 8 deletions chain-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ name = "client"
path = "src/client.rs"

[dependencies]
abomonation = "0.7.3"
anyhow = "1.0.72"
camino = "1.1.6"
clap = "4.3.17"
ff = "0.13"
abomonation = { workspace = true }
anyhow = { workspace = true }
camino = { workspace = true}
clap = { workspace = true}
ff = { workspace = true }
lurk = { path = "../" }
halo2curves = { version = "0.6.0", features = ["bits", "derive_serde"] }
nova = { git = "https://github.com/lurk-lab/arecibo", branch = "dev", package = "arecibo", features = ["abomonate"]}
once_cell = "1.18.0"
nova = { workspace = true }
once_cell = {workspace = true }
prost = "0.12"
rustyline = "14.0"
serde = "1.0"
serde = { workspace = true }
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
tonic = "0.11"

Expand Down
3 changes: 3 additions & 0 deletions chain-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ where
let proof = proof
.compress(pp)
.map_err(|e| Status::internal(e.to_string()))?;
// the above compression operated on a recursive proof, so the following `into_owned()` should
// not involve cloning
let proof = proof
.into_owned()
.get_compressed()
.ok_or(Status::internal("Failed to retrieve the compressed SNARK"))?;

Expand Down
8 changes: 6 additions & 2 deletions src/cli/repl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,11 @@ where
let proof = proof.compress(&pp)?;
assert_eq!(self.rc * num_steps, pad(n_frames, self.rc));
assert!(proof.verify(&pp, &public_inputs, &public_outputs)?);
(LurkProofWrapper::Nova(proof), public_inputs, public_outputs)
(
LurkProofWrapper::Nova(proof.into_owned()),
public_inputs,
public_outputs,
)
}
Backend::SuperNova => {
let prover = SuperNovaProver::<_, C>::new(self.rc, self.lang.clone());
Expand All @@ -375,7 +379,7 @@ where
let proof = proof.compress(&pp)?;
assert!(proof.verify(&pp, &public_inputs, &public_outputs)?);
(
LurkProofWrapper::SuperNova(proof),
LurkProofWrapper::SuperNova(proof.into_owned()),
public_inputs,
public_outputs,
)
Expand Down
10 changes: 5 additions & 5 deletions src/coroutine/memoset/prove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use nova::{
Dual as DualEng,
},
};
use std::marker::PhantomData;
use std::{borrow::Cow, marker::PhantomData};

/// Number of arguments a coroutine takes: CEK arguments + memoset arguments
const COROUTINE_ARITY: usize = 12;
Expand Down Expand Up @@ -146,13 +146,13 @@ impl<'a, F: CurveCycleEquipped, Q: Query<F> + Send + Sync>
))
}

fn compress(self, pp: &PublicParams<F>) -> Result<Self, ProofError> {
match &self {
fn compress(&self, pp: &PublicParams<F>) -> Result<Cow<'_, Self>, ProofError> {
match self {
Self::Recursive(recursive_snark, _) => {
let snark = CompressedSNARK::prove(&pp.pp, pp.pk(), recursive_snark)?;
Ok(Self::Compressed(Box::new(snark), PhantomData))
Ok(Cow::Owned(Self::Compressed(Box::new(snark), PhantomData)))
}
Self::Compressed(..) => Ok(self),
Self::Compressed(..) => Ok(Cow::Borrowed(self)),
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub mod supernova;
mod tests;

use ff::Field;
use std::sync::Arc;
use std::{borrow::Cow, sync::Arc};

use crate::{
coprocessor::Coprocessor,
Expand Down Expand Up @@ -88,7 +88,7 @@ pub trait Provable<F: LurkField> {
/// Trait to abstract Nova and SuperNova proofs
pub trait RecursiveSNARKTrait<F: CurveCycleEquipped, M>
where
Self: Sized,
Self: Sized + Clone,
{
/// Associated type for public parameters
type PublicParams;
Expand All @@ -110,7 +110,7 @@ where
) -> Result<Self, ProofError>;

/// Compress a proof
fn compress(self, pp: &Self::PublicParams) -> Result<Self, ProofError>;
fn compress(&self, pp: &Self::PublicParams) -> Result<Cow<'_, Self>, ProofError>;

/// Verify the proof given the public parameters, the input and output values
fn verify(&self, pp: &Self::PublicParams, z0: &[F], zi: &[F]) -> Result<bool, Self::ErrorType>;
Expand Down
27 changes: 15 additions & 12 deletions src/proof/nova.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use once_cell::sync::OnceCell;
use pasta_curves::pallas;
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
marker::PhantomData,
sync::{Arc, Mutex},
};
Expand Down Expand Up @@ -161,7 +162,7 @@ impl<F: CurveCycleEquipped> From<NovaPublicParams<F>> for PublicParams<F> {
}

/// An enum representing the two types of proofs that can be generated and verified.
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
#[serde(bound = "")]
pub enum Proof<F: CurveCycleEquipped, S> {
/// A proof for the intermediate steps of a recursive computation along with
Expand Down Expand Up @@ -331,18 +332,20 @@ impl<'a, F: CurveCycleEquipped, C: Coprocessor<F>> RecursiveSNARKTrait<F, C1LEM<
))
}

fn compress(self, pp: &PublicParams<F>) -> Result<Self, ProofError> {
fn compress(&self, pp: &PublicParams<F>) -> Result<Cow<'_, Self>, ProofError> {
match self {
Self::Recursive(recursive_snark, num_steps, _phantom) => Ok(Self::Compressed(
Box::new(CompressedSNARK::<_, SS1<F>, SS2<F>>::prove(
&pp.pp,
pp.pk(),
&recursive_snark,
)?),
num_steps,
PhantomData,
)),
Self::Compressed(..) => Ok(self),
Self::Recursive(recursive_snark, num_steps, _phantom) => {
Ok(Cow::Owned(Self::Compressed(
Box::new(CompressedSNARK::<_, SS1<F>, SS2<F>>::prove(
&pp.pp,
pp.pk(),
recursive_snark,
)?),
*num_steps,
PhantomData,
)))
}
Self::Compressed(..) => Ok(Cow::Borrowed(self)),
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/proof/supernova.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use once_cell::sync::OnceCell;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
marker::PhantomData,
ops::Index,
sync::{Arc, Mutex},
Expand Down Expand Up @@ -137,7 +138,7 @@ pub fn public_params<F: CurveCycleEquipped, C: Coprocessor<F>>(
}

/// An enum representing the two types of proofs that can be generated and verified.
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
#[serde(bound = "")]
pub enum Proof<F: CurveCycleEquipped, S> {
/// A proof for the intermediate steps of a recursive computation
Expand Down Expand Up @@ -314,14 +315,14 @@ impl<'a, F: CurveCycleEquipped, C: Coprocessor<F>> RecursiveSNARKTrait<F, C1LEM<
))
}

fn compress(self, pp: &PublicParams<F>) -> Result<Self, ProofError> {
fn compress(&self, pp: &PublicParams<F>) -> Result<Cow<'_, Self>, ProofError> {
match &self {
Self::Recursive(recursive_snark, _phantom) => {
let snark =
CompressedSNARK::<_, SS1<F>, SS2<F>>::prove(&pp.pp, pp.pk(), recursive_snark)?;
Ok(Self::Compressed(Box::new(snark), PhantomData))
Ok(Cow::Owned(Self::Compressed(Box::new(snark), PhantomData)))
}
Self::Compressed(..) => Ok(self),
Self::Compressed(..) => Ok(Cow::Borrowed(self)),
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/proof/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ fn nova_test_full_aux2<'a, F: CurveCycleEquipped, C: Coprocessor<F> + 'a>(
assert!(res.unwrap());

let compressed: crate::proof::nova::Proof<F, C1LEM<'a, F, C>> =
proof.compress(&pp).unwrap();
proof.compress(&pp).unwrap().into_owned();
let res2 = compressed.verify(&pp, &z0, &zi);

assert!(res2.unwrap());
Expand Down

1 comment on commit 0d2ae13

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Table of Contents

Overview

This benchmark report shows the Fibonacci GPU benchmark.
NVIDIA L4
Intel(R) Xeon(R) CPU @ 2.20GHz
32 vCPUs
125 GB RAM
Workflow run: https://github.com/lurk-lab/lurk-rs/actions/runs/8344216227

Benchmark Results

LEM Fibonacci Prove - rc = 100

ref=4266b151841e4f10e4245856fc465ae08494bda6 ref=0d2ae13ceb55963aa4be94b65fb3d0194f92b411
num-100 1.47 s (✅ 1.00x) 1.46 s (✅ 1.00x faster)
num-200 2.80 s (✅ 1.00x) 2.78 s (✅ 1.00x faster)

LEM Fibonacci Prove - rc = 600

ref=4266b151841e4f10e4245856fc465ae08494bda6 ref=0d2ae13ceb55963aa4be94b65fb3d0194f92b411
num-100 1.84 s (✅ 1.00x) 1.86 s (✅ 1.01x slower)
num-200 3.04 s (✅ 1.00x) 3.04 s (✅ 1.00x slower)

Made with criterion-table

Please sign in to comment.