Feat/disk cache (#354)
- Bump rust version to `nightly-2025-07-02` because some of the nightly features we were using have been stabilized. - Introduce feature `disk_cache` which enables caching to disk. Each time an artifact is retrieved from the cache it will be read and deserialized. On a cache miss the artifact will be created, serialized and stored to disk. - Introduce feature `mem_cache` which enables caching to memory. All cached artifacts are kept in memory after they are created. The mem cache implementation avoids cloning of artifacts by extending their lifetime to `'static`. This is `unsafe` code, but I argue that this usage is safe. - Add a `build.rs` - When the feature `disk_cache` is enabled, the `build.rs` will inject env variables to the process with the git commit information, which is used to index the cached artifacts - Replace all previous cached artifacts from `LazyStatic` methods that call the cache API - Derive `Serialize, Deserialize` for all `*Target` types so that they can be serialized for caching to disk - Add finer level of caching: now we cache the `CircuitData` and `VerifierData` independently. The reason for this is that `CircuitData` is a very big artifact which is not needed for verification. So by only accessing `VerifierData` in verification we don't pay a big overhead for reading from disk and deserializing - Add missing artifacts to the cache: like the `CircuitData` for the `MainPod` indexed by `Params` - Add helper types to serialize and deserialize `CircuitData`, `CommonData` and `VerifierData` with the set of gates and generators used in the recursive MainPod circuit - Tweak the ids of our custom gates so that they remain unique when their generic parameters change - Bugfix: several tests were using the standard `vd_set` but were using MainPod circuits with non-default parameters. This was working before because there was a bug: the MainPod circuit was reporting that the used verifier data was the standard one instead of picking the one corresponding to it's own Params. Summary of breaking changes: - One and only one of the features `mem_cache` or `disk_cache` need to be enabled. By default it's `mem_cache` - To enable the `disk_cache` you need to disable the default features like this: `--no-default-features --features=backend_plonky2,zk,disk_cache` - Removed `DEFAULT_PARAMS`, instead use `Params::default()` - Removed `STANDARD_REC_MAIN_POD_CIRCUIT_DATA`, instead use `cache_get_standard_rec_main_pod_common_circuit_data` - The library is now using `nightly-2025-07-02`. Some rust language features are unstable in previous versions.
This commit is contained in:
parent
745d654048
commit
8429cd224d
35 changed files with 831 additions and 207 deletions
|
|
@ -4,31 +4,34 @@ use std::{any::Any, iter, sync::Arc};
|
|||
|
||||
use itertools::Itertools;
|
||||
pub use operation::*;
|
||||
use plonky2::{
|
||||
hash::poseidon::PoseidonHash,
|
||||
plonk::{circuit_data::CommonCircuitData, config::Hasher},
|
||||
};
|
||||
use plonky2::{hash::poseidon::PoseidonHash, plonk::config::Hasher};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use statement::*;
|
||||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{Proof, ProofWithPublicInputs, VerifierOnlyCircuitData, D},
|
||||
basetypes::{CircuitData, Proof, ProofWithPublicInputs, VerifierOnlyCircuitData},
|
||||
cache::{self, CacheEntry},
|
||||
cache_get_standard_rec_main_pod_common_circuit_data,
|
||||
circuits::mainpod::{CustomPredicateVerification, MainPodVerifyInput, MainPodVerifyTarget},
|
||||
deserialize_proof,
|
||||
emptypod::EmptyPod,
|
||||
error::{Error, Result},
|
||||
mock::emptypod::MockEmptyPod,
|
||||
primitives::merkletree::MerkleClaimAndProof,
|
||||
recursion::{hash_verifier_data, RecursiveCircuit, RecursiveParams},
|
||||
recursion::{
|
||||
hash_verifier_data, prove_rec_circuit, RecursiveCircuit, RecursiveCircuitTarget,
|
||||
},
|
||||
serialization::{
|
||||
CircuitDataSerializer, CommonCircuitDataSerializer, VerifierCircuitDataSerializer,
|
||||
},
|
||||
serialize_proof,
|
||||
signedpod::SignedPod,
|
||||
STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
|
||||
},
|
||||
middleware::{
|
||||
self, resolve_wildcard_values, value_from_op, AnchoredKey, CustomPredicateBatch, Hash,
|
||||
MainPodInputs, NativeOperation, OperationType, Params, Pod, PodId, PodProver, PodType,
|
||||
RecursivePod, StatementArg, ToFields, VDSet, F, KEY_TYPE, SELF,
|
||||
RecursivePod, StatementArg, ToFields, VDSet, KEY_TYPE, SELF,
|
||||
},
|
||||
timed,
|
||||
};
|
||||
|
|
@ -434,24 +437,6 @@ impl PodProver for Prover {
|
|||
vd_set: &VDSet,
|
||||
inputs: MainPodInputs,
|
||||
) -> Result<Box<dyn RecursivePod>> {
|
||||
let rec_circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||
let (main_pod_target, circuit_data) =
|
||||
RecursiveCircuit::<MainPodVerifyTarget>::target_and_circuit_data_padded(
|
||||
params.max_input_recursive_pods,
|
||||
&rec_circuit_data.common,
|
||||
params,
|
||||
)?;
|
||||
let rec_params = RecursiveParams {
|
||||
arity: params.max_input_recursive_pods,
|
||||
common_data: circuit_data.common.clone(),
|
||||
verifier_data: circuit_data.verifier_data(),
|
||||
};
|
||||
let main_pod = RecursiveCircuit {
|
||||
params: rec_params,
|
||||
prover: circuit_data.prover_data(),
|
||||
target: main_pod_target,
|
||||
};
|
||||
|
||||
let signed_pods_input: Vec<SignedPod> = inputs
|
||||
.signed_pods
|
||||
.iter()
|
||||
|
|
@ -541,9 +526,17 @@ impl PodProver for Prover {
|
|||
custom_predicate_batches,
|
||||
custom_predicate_verifications,
|
||||
};
|
||||
|
||||
let (main_pod_target, circuit_data) = &*cache_get_rec_main_pod_circuit_data(params);
|
||||
let proof_with_pis = timed!(
|
||||
"MainPod::prove",
|
||||
main_pod.prove(&input, proofs, verifier_datas)?
|
||||
prove_rec_circuit(
|
||||
main_pod_target,
|
||||
circuit_data,
|
||||
&input,
|
||||
proofs,
|
||||
verifier_datas
|
||||
)?
|
||||
);
|
||||
|
||||
Ok(Box::new(MainPod {
|
||||
|
|
@ -570,21 +563,59 @@ pub struct MainPod {
|
|||
proof: Proof,
|
||||
}
|
||||
|
||||
// This is a helper function to get the CommonCircuitData necessary to decode
|
||||
// a serialized proof. At some point in the future, this data may be available
|
||||
// as a constant or with static initialization, but in the meantime we can
|
||||
// generate it on-demand.
|
||||
pub fn get_common_data(params: &Params) -> Result<CommonCircuitData<F, D>, Error> {
|
||||
// TODO: Cache this somehow
|
||||
// https://github.com/0xPARC/pod2/issues/247
|
||||
let rec_circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||
let (_, circuit_data) =
|
||||
pub(crate) fn rec_main_pod_circuit_data(
|
||||
params: &Params,
|
||||
) -> (RecursiveCircuitTarget<MainPodVerifyTarget>, CircuitData) {
|
||||
let rec_common_circuit_data = cache_get_standard_rec_main_pod_common_circuit_data();
|
||||
timed!(
|
||||
"recursive MainPod circuit_data padded",
|
||||
RecursiveCircuit::<MainPodVerifyTarget>::target_and_circuit_data_padded(
|
||||
params.max_input_recursive_pods,
|
||||
&rec_circuit_data.common,
|
||||
&rec_common_circuit_data,
|
||||
params,
|
||||
)?;
|
||||
Ok(circuit_data.common.clone())
|
||||
)
|
||||
.expect("calculate target_and_circuit_data_padded")
|
||||
)
|
||||
}
|
||||
|
||||
fn cache_get_rec_main_pod_circuit_data(
|
||||
params: &Params,
|
||||
) -> CacheEntry<(
|
||||
RecursiveCircuitTarget<MainPodVerifyTarget>,
|
||||
CircuitDataSerializer,
|
||||
)> {
|
||||
// TODO(Edu): I believe that the standard_rec_main_pod_circuit data is the same as this when
|
||||
// the params are Default: we're padding the circuit to itself, so we get the original one?
|
||||
// If this is true we can deduplicate this cache entry because both rec_main_pod_circuit_data
|
||||
// and standard_rec_main_pod_circuit_data are indexed by Params. This can be easily tested by
|
||||
// comparing the cached artifacts on disk :)
|
||||
cache::get("rec_main_pod_circuit_data", params, |params| {
|
||||
let (target, circuit_data) = rec_main_pod_circuit_data(params);
|
||||
(target, CircuitDataSerializer(circuit_data))
|
||||
})
|
||||
.expect("cache ok")
|
||||
}
|
||||
|
||||
pub fn cache_get_rec_main_pod_verifier_circuit_data(
|
||||
params: &Params,
|
||||
) -> CacheEntry<VerifierCircuitDataSerializer> {
|
||||
cache::get("rec_main_pod_verifier_circuit_data", params, |params| {
|
||||
let (_, rec_main_pod_circuit_data_padded) = &*cache_get_rec_main_pod_circuit_data(params);
|
||||
VerifierCircuitDataSerializer(rec_main_pod_circuit_data_padded.verifier_data().clone())
|
||||
})
|
||||
.expect("cache ok")
|
||||
}
|
||||
|
||||
// This is a helper function to get the CommonCircuitData necessary to decode
|
||||
// a serialized proof.
|
||||
pub fn cache_get_rec_main_pod_common_circuit_data(
|
||||
params: &Params,
|
||||
) -> CacheEntry<CommonCircuitDataSerializer> {
|
||||
cache::get("rec_main_pod_common_circuit_data", params, |params| {
|
||||
let (_, rec_main_pod_circuit_data_padded) = &*cache_get_rec_main_pod_circuit_data(params);
|
||||
CommonCircuitDataSerializer(rec_main_pod_circuit_data_padded.common.clone())
|
||||
})
|
||||
.expect("cache ok")
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
|
@ -626,22 +657,15 @@ impl Pod for MainPod {
|
|||
}
|
||||
|
||||
// 1, 3, 4, 5 verification via the zkSNARK proof
|
||||
let rec_circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||
// TODO: cache these artefacts
|
||||
// https://github.com/0xPARC/pod2/issues/247
|
||||
let (_, circuit_data) =
|
||||
RecursiveCircuit::<MainPodVerifyTarget>::target_and_circuit_data_padded(
|
||||
self.params.max_input_recursive_pods,
|
||||
&rec_circuit_data.common,
|
||||
&self.params,
|
||||
)?;
|
||||
let rec_main_pod_verifier_circuit_data =
|
||||
&*cache_get_rec_main_pod_verifier_circuit_data(&self.params);
|
||||
let public_inputs = id
|
||||
.to_fields(&self.params)
|
||||
.iter()
|
||||
.chain(self.vd_set.root().0.iter())
|
||||
.cloned()
|
||||
.collect_vec();
|
||||
circuit_data
|
||||
rec_main_pod_verifier_circuit_data
|
||||
.verify(ProofWithPublicInputs {
|
||||
proof: self.proof.clone(),
|
||||
public_inputs,
|
||||
|
|
@ -675,8 +699,9 @@ impl Pod for MainPod {
|
|||
|
||||
impl RecursivePod for MainPod {
|
||||
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||
let data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||
data.verifier_only.clone()
|
||||
let rec_main_pod_verifier_circuit_data =
|
||||
cache_get_rec_main_pod_verifier_circuit_data(&self.params);
|
||||
rec_main_pod_verifier_circuit_data.verifier_only.clone()
|
||||
}
|
||||
fn proof(&self) -> Proof {
|
||||
self.proof.clone()
|
||||
|
|
@ -691,7 +716,7 @@ impl RecursivePod for MainPod {
|
|||
id: PodId,
|
||||
) -> Result<Box<dyn RecursivePod>> {
|
||||
let data: Data = serde_json::from_value(data)?;
|
||||
let common = get_common_data(¶ms)?;
|
||||
let common = cache_get_rec_main_pod_common_circuit_data(¶ms);
|
||||
let proof = deserialize_proof(&common, &data.proof)?;
|
||||
Ok(Box::new(Self {
|
||||
params,
|
||||
|
|
@ -719,7 +744,8 @@ pub mod tests {
|
|||
self, literal, CustomPredicateBatchBuilder, MainPodBuilder, StatementTmplBuilder as STB,
|
||||
},
|
||||
middleware::{
|
||||
self, containers::Set, CustomPredicateRef, NativePredicate as NP, DEFAULT_VD_SET,
|
||||
self, containers::Set, CustomPredicateRef, NativePredicate as NP, DEFAULT_VD_LIST,
|
||||
DEFAULT_VD_SET,
|
||||
},
|
||||
op,
|
||||
};
|
||||
|
|
@ -735,7 +761,9 @@ pub mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
println!("{:#?}", params);
|
||||
let vd_set = &*DEFAULT_VD_SET;
|
||||
let mut vds = DEFAULT_VD_LIST.clone();
|
||||
vds.push(rec_main_pod_circuit_data(¶ms).1.verifier_only.clone());
|
||||
let vd_set = VDSet::new(params.max_depth_mt_vds, &vds).unwrap();
|
||||
|
||||
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
|
||||
zu_kyc_sign_pod_builders(¶ms);
|
||||
|
|
@ -747,7 +775,7 @@ pub mod tests {
|
|||
let sanction_list_pod = sanction_list_builder.sign(&signer)?;
|
||||
let kyc_builder = zu_kyc_pod_builder(
|
||||
¶ms,
|
||||
vd_set,
|
||||
&vd_set,
|
||||
&gov_id_pod,
|
||||
&pay_stub_pod,
|
||||
&sanction_list_pod,
|
||||
|
|
@ -772,7 +800,9 @@ pub mod tests {
|
|||
max_input_pods_public_statements: 10,
|
||||
..Default::default()
|
||||
};
|
||||
let vd_set = &*DEFAULT_VD_SET;
|
||||
let mut vds = DEFAULT_VD_LIST.clone();
|
||||
vds.push(rec_main_pod_circuit_data(¶ms).1.verifier_only.clone());
|
||||
let vd_set = VDSet::new(params.max_depth_mt_vds, &vds).unwrap();
|
||||
|
||||
let mut gov_id_builder = frontend::SignedPodBuilder::new(¶ms);
|
||||
gov_id_builder.insert("idNumber", "4242424242");
|
||||
|
|
@ -781,7 +811,7 @@ pub mod tests {
|
|||
let signer = Signer(SecretKey(42u64.into()));
|
||||
let gov_id = gov_id_builder.sign(&signer).unwrap();
|
||||
let now_minus_18y: i64 = 1169909388;
|
||||
let mut kyc_builder = frontend::MainPodBuilder::new(¶ms, vd_set);
|
||||
let mut kyc_builder = frontend::MainPodBuilder::new(¶ms, &vd_set);
|
||||
kyc_builder.add_signed_pod(&gov_id);
|
||||
kyc_builder
|
||||
.pub_op(op!(lt, (&gov_id, "dateOfBirth"), now_minus_18y))
|
||||
|
|
@ -827,9 +857,11 @@ pub mod tests {
|
|||
max_depth_mt_containers: 4,
|
||||
max_depth_mt_vds: 6,
|
||||
};
|
||||
let vd_set = &*DEFAULT_VD_SET;
|
||||
let mut vds = DEFAULT_VD_LIST.clone();
|
||||
vds.push(rec_main_pod_circuit_data(¶ms).1.verifier_only.clone());
|
||||
let vd_set = VDSet::new(params.max_depth_mt_vds, &vds).unwrap();
|
||||
|
||||
let pod_builder = frontend::MainPodBuilder::new(¶ms, vd_set);
|
||||
let pod_builder = frontend::MainPodBuilder::new(¶ms, &vd_set);
|
||||
|
||||
// Mock
|
||||
let prover = MockProver {};
|
||||
|
|
@ -889,7 +921,9 @@ pub mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
println!("{:#?}", params);
|
||||
let vd_set = &*DEFAULT_VD_SET;
|
||||
let mut vds = DEFAULT_VD_LIST.clone();
|
||||
vds.push(rec_main_pod_circuit_data(¶ms).1.verifier_only.clone());
|
||||
let vd_set = VDSet::new(params.max_depth_mt_vds, &vds).unwrap();
|
||||
|
||||
let mut cpb_builder = CustomPredicateBatchBuilder::new(params.clone(), "cpb".into());
|
||||
let stb0 = STB::new(NP::Equal).arg(("id", "score")).arg(literal(42));
|
||||
|
|
@ -908,7 +942,7 @@ pub mod tests {
|
|||
let cpb_and = CustomPredicateRef::new(cpb.clone(), 0);
|
||||
let _cpb_or = CustomPredicateRef::new(cpb.clone(), 1);
|
||||
|
||||
let mut pod_builder = MainPodBuilder::new(¶ms, vd_set);
|
||||
let mut pod_builder = MainPodBuilder::new(¶ms, &vd_set);
|
||||
|
||||
let st0 = pod_builder.priv_op(op!(new_entry, "score", 42))?;
|
||||
let st1 = pod_builder.priv_op(op!(new_entry, "key", 42))?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue