Skip to content

Commit

Permalink
Merge pull request #2971 from o1-labs/martin/saffron-proof-of-storage…
Browse files Browse the repository at this point in the history
…-clean

Proof of Storage
  • Loading branch information
martyall authored Jan 30, 2025
2 parents 563901a + 97ee9f7 commit 8818a11
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions saffron/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mina-curves.workspace = true
mina-poseidon.workspace = true
o1-utils.workspace = true
poly-commitment.workspace = true
rand.workspace = true
rayon.workspace = true
rmp-serde.workspace = true
serde.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions saffron/src/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl<G: CommitmentCurve> FieldBlob<G> {
}

#[cfg(test)]
mod blob_test_utils {
pub mod test_utils {
use proptest::prelude::*;

#[derive(Debug)]
Expand Down Expand Up @@ -171,10 +171,10 @@ mod tests {

use super::*;
use ark_poly::Radix2EvaluationDomain;
use blob_test_utils::*;
use mina_curves::pasta::{Fp, Vesta};
use once_cell::sync::Lazy;
use proptest::prelude::*;
use test_utils::*;

static SRS: Lazy<SRS<Vesta>> = Lazy::new(|| {
if let Ok(srs) = std::env::var("SRS_FILEPATH") {
Expand Down
1 change: 1 addition & 0 deletions saffron/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod blob;
pub mod cli;
pub mod commitment;
pub mod env;
pub mod proof;
pub mod utils;
171 changes: 171 additions & 0 deletions saffron/src/proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
use crate::blob::FieldBlob;
use ark_ec::AffineRepr;
use ark_ff::{One, PrimeField, Zero};
use ark_poly::{univariate::DensePolynomial, Polynomial, Radix2EvaluationDomain as D};
use kimchi::curve::KimchiCurve;
use mina_poseidon::FqSponge;
use o1_utils::ExtendedDensePolynomial;
use poly_commitment::{
commitment::{absorb_commitment, BatchEvaluationProof, Evaluation},
ipa::{OpeningProof, SRS},
utils::DensePolynomialOrEvaluations,
PolyComm,
};
use rand::rngs::OsRng;
use tracing::instrument;

#[instrument(skip_all, level = "debug")]
pub fn storage_proof<G: KimchiCurve, EFqSponge: Clone + FqSponge<G::BaseField, G, G::ScalarField>>(
srs: &SRS<G>,
group_map: &G::Map,
blob: FieldBlob<G>,
evaluation_point: G::ScalarField,
rng: &mut OsRng,
) -> (G::ScalarField, OpeningProof<G>)
where
G::BaseField: PrimeField,
{
let alpha = {
let mut sponge = EFqSponge::new(G::other_curve_sponge_params());
for commitment in &blob.commitments {
absorb_commitment(&mut sponge, commitment)
}
sponge.challenge()
};
let p = {
let init = (DensePolynomial::zero(), G::ScalarField::one());
blob.data
.into_iter()
.fold(init, |(acc_poly, curr_power), curr_poly| {
(acc_poly + curr_poly.scale(curr_power), curr_power * alpha)
})
.0
};
let evaluation = p.evaluate(&evaluation_point);
let opening_proof_sponge = {
let mut sponge = EFqSponge::new(G::other_curve_sponge_params());
// TODO: check and see if we need to also absorb the absorb the poly cm
// see https://github.com/o1-labs/proof-systems/blob/feature/test-data-storage-commitments/data-storage/src/main.rs#L265-L269
sponge.absorb_fr(&[evaluation]);
sponge
};
let proof = srs.open(
group_map,
&[(
DensePolynomialOrEvaluations::<<G as AffineRepr>::ScalarField, D<G::ScalarField>> ::DensePolynomial(
&p,
),
PolyComm {
chunks: vec![G::ScalarField::zero()],
},
)],
&[evaluation_point],
G::ScalarField::one(), // Single evaluation, so we don't care
G::ScalarField::one(), // Single evaluation, so we don't care
opening_proof_sponge,
rng,
);
(evaluation, proof)
}

#[instrument(skip_all, level = "debug")]
pub fn verify_storage_proof<
G: KimchiCurve,
EFqSponge: Clone + FqSponge<G::BaseField, G, G::ScalarField>,
>(
srs: &SRS<G>,
group_map: &G::Map,
commitment: PolyComm<G>,
evaluation_point: G::ScalarField,
evaluation: G::ScalarField,
opening_proof: &OpeningProof<G>,
rng: &mut OsRng,
) -> bool
where
G::BaseField: PrimeField,
{
let mut opening_proof_sponge = EFqSponge::new(G::other_curve_sponge_params());
opening_proof_sponge.absorb_fr(&[evaluation]);

srs.verify(
group_map,
&mut [BatchEvaluationProof {
sponge: opening_proof_sponge.clone(),
evaluation_points: vec![evaluation_point],
polyscale: G::ScalarField::one(),
evalscale: G::ScalarField::one(),
evaluations: vec![Evaluation {
commitment,
evaluations: vec![vec![evaluation]],
}],
opening: opening_proof,
combined_inner_product: evaluation,
}],
rng,
)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
blob::test_utils::*,
commitment::{commit_to_field_elems, fold_commitments},
env,
utils::encode_for_domain,
};
use ark_poly::{EvaluationDomain, Radix2EvaluationDomain};
use ark_std::UniformRand;
use kimchi::groupmap::GroupMap;
use mina_curves::pasta::{Fp, Vesta, VestaParameters};
use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge};
use once_cell::sync::Lazy;
use poly_commitment::{commitment::CommitmentCurve, ipa::SRS, SRS as _};
use proptest::prelude::*;

static SRS: Lazy<SRS<Vesta>> = Lazy::new(|| {
if let Ok(srs) = std::env::var("SRS_FILEPATH") {
env::get_srs_from_cache(srs)
} else {
SRS::create(1 << 16)
}
});

static DOMAIN: Lazy<Radix2EvaluationDomain<Fp>> =
Lazy::new(|| Radix2EvaluationDomain::new(SRS.size()).unwrap());

static GROUP_MAP: Lazy<<Vesta as CommitmentCurve>::Map> =
Lazy::new(<Vesta as CommitmentCurve>::Map::setup);

proptest! {
#![proptest_config(ProptestConfig::with_cases(5))]
#[test]
fn test_storage_prove_verify(BlobData(data) in BlobData::arbitrary()) {
let mut rng = OsRng;
let commitment = {
let field_elems = encode_for_domain(&*DOMAIN, &data);
let user_commitments = commit_to_field_elems(&*SRS, *DOMAIN, field_elems);
let mut fq_sponge = DefaultFqSponge::<VestaParameters, PlonkSpongeConstantsKimchi>::new(
mina_poseidon::pasta::fq_kimchi::static_params(),
);
fold_commitments(&mut fq_sponge, &user_commitments)
};
let blob = FieldBlob::<Vesta>::encode(&*SRS, *DOMAIN, &data);
let evaluation_point = Fp::rand(&mut rng);
let (evaluation, proof) = storage_proof::<
Vesta,
DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>,
>(&*SRS, &*GROUP_MAP, blob, evaluation_point, &mut rng);
let res = verify_storage_proof::<Vesta, DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>>(
&*SRS,
&*GROUP_MAP,
commitment,
evaluation_point,
evaluation,
&proof,
&mut rng,
);
prop_assert!(res);
}
}
}

0 comments on commit 8818a11

Please sign in to comment.