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
|
|
@ -16,11 +16,12 @@ use plonky2::{
|
|||
plonk::{circuit_builder::CircuitBuilder, circuit_data::CommonCircuitData},
|
||||
util::serialization::{Buffer, IoResult, Read, Write},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::backends::plonky2::basetypes::{D, F};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ConditionalZeroGenerator<F: RichField + Extendable<D>, const D: usize> {
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct ConditionalZeroGenerator<F: RichField + Extendable<D>, const D: usize> {
|
||||
if_zero: Target,
|
||||
then_zero: Target,
|
||||
quot: Target,
|
||||
|
|
@ -78,9 +79,11 @@ impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F, D>
|
|||
|
||||
/// A big integer, represented in base `2^32` with 10 digits, in little endian
|
||||
/// form.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BigUInt320Target {
|
||||
#[serde(with = "serde_arrays")]
|
||||
pub limbs: [Target; 10],
|
||||
#[serde(with = "serde_arrays")]
|
||||
pub bits: [BoolTarget; 320],
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +316,7 @@ fn biguint_limbs_to_bits(builder: &mut CircuitBuilder<F, D>, limbs: &[Target]) -
|
|||
Copied from https://github.com/0xPolygonZero/plonky2/blob/82791c4809d6275682c34b926390ecdbdc2a5297/plonky2/src/gadgets/range_check.rs#L62
|
||||
*/
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct LowHighGenerator {
|
||||
integer: Target,
|
||||
n_log: usize,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ pub fn ec_field_sqrt(x: &ECField) -> Option<ECField> {
|
|||
]);
|
||||
// Compute x^((r-1)/2) = x^(p*((1+p)/2)*(1+p^2))
|
||||
let x1 = x.frobenius();
|
||||
#[allow(clippy::manual_div_ceil)]
|
||||
let x2 = x1.exp_u64((1 + GoldilocksField::ORDER) / 2);
|
||||
let den = x2 * x2.repeated_frobenius(2);
|
||||
Some(num / den)
|
||||
|
|
@ -440,7 +441,7 @@ impl Mul<Point> for &BigUint {
|
|||
|
||||
type FieldTarget = OEFTarget<5, QuinticExtension<GoldilocksField>>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct PointTarget {
|
||||
pub x: FieldTarget,
|
||||
pub u: FieldTarget,
|
||||
|
|
@ -470,8 +471,8 @@ impl PointTarget {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct PointSquareRootGenerator {
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub(crate) struct PointSquareRootGenerator {
|
||||
pub orig: PointTarget,
|
||||
pub sqrt: PointTarget,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use plonky2::{
|
|||
plonk::{circuit_builder::CircuitBuilder, circuit_data::CommonCircuitData},
|
||||
util::serialization::{Buffer, IoError, Read, Write},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
//use super::gates::field::NNFMulGate;
|
||||
use crate::{
|
||||
|
|
@ -83,8 +84,9 @@ pub trait CircuitBuilderNNF<
|
|||
}
|
||||
|
||||
/// Target type modelled on OEF.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OEFTarget<const DEG: usize, NNF: OEF<DEG>> {
|
||||
#[serde(with = "serde_arrays")]
|
||||
pub components: [Target; DEG],
|
||||
_phantom_data: PhantomData<NNF>,
|
||||
}
|
||||
|
|
@ -106,8 +108,8 @@ impl<const DEG: usize, NNF: OEF<DEG>> Default for OEFTarget<DEG, NNF> {
|
|||
|
||||
/// Quotient generator for OEF targets. Allows us to automagically
|
||||
/// generate quotients as witnesses.
|
||||
#[derive(Debug, Default)]
|
||||
struct QuotientGeneratorOEF<const DEG: usize, NNF: OEF<DEG>> {
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct QuotientGeneratorOEF<const DEG: usize, NNF: OEF<DEG>> {
|
||||
numerator: OEFTarget<DEG, NNF>,
|
||||
denominator: OEFTarget<DEG, NNF>,
|
||||
quotient: OEFTarget<DEG, NNF>,
|
||||
|
|
@ -121,7 +123,11 @@ impl<
|
|||
> SimpleGenerator<F, D> for QuotientGeneratorOEF<DEG, NNF>
|
||||
{
|
||||
fn id(&self) -> String {
|
||||
"QuotientGeneratorOEF".to_string()
|
||||
format!(
|
||||
"QuotientGeneratorOEF<{}, {}>",
|
||||
DEG,
|
||||
std::any::type_name::<NNF>()
|
||||
)
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<Target> {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::backends::plonky2::primitives::ec::{
|
|||
/// operation when all its witness wire values are zero (so that when the gate is partially used,
|
||||
/// the unused slots still pass the constraints). This is the reason why this gate doesn't add the
|
||||
/// final offset: if it did, the constraints wouldn't pass on the zero witness values.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ECAddHomogOffset;
|
||||
|
||||
impl SimpleGate for ECAddHomogOffset {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ pub struct RecursiveGateAdapter<const D: usize, G: SimpleGate> {
|
|||
_gate: PhantomData<G>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct RecursiveGenerator<const D: usize, G: SimpleGate> {
|
||||
row: usize,
|
||||
index: usize,
|
||||
|
|
@ -175,7 +175,7 @@ where
|
|||
G::F: RichField + Extendable<D> + Extendable<1>,
|
||||
{
|
||||
fn id(&self) -> String {
|
||||
G::ID.to_string()
|
||||
format!("GateAdapter<{}>", std::any::type_name::<G>())
|
||||
}
|
||||
|
||||
fn serialize(
|
||||
|
|
@ -336,7 +336,7 @@ where
|
|||
}
|
||||
|
||||
fn id(&self) -> String {
|
||||
format!("Generator<{},{}>", D, G::ID)
|
||||
format!("RecursiveGenerator<{}, {}>", D, std::any::type_name::<G>())
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<Target> {
|
||||
|
|
@ -374,7 +374,11 @@ where
|
|||
F: RichField + Extendable<D>,
|
||||
{
|
||||
fn id(&self) -> String {
|
||||
format!("Recursive<{},{}>", D, G::ID)
|
||||
format!(
|
||||
"RecursiveGateAdapter<{}, {}>",
|
||||
D,
|
||||
std::any::type_name::<G>()
|
||||
)
|
||||
}
|
||||
|
||||
fn serialize(&self, dst: &mut Vec<u8>, _common_data: &CommonCircuitData<F, D>) -> IoResult<()> {
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ impl<'de> Deserialize<'de> for Signature {
|
|||
}
|
||||
|
||||
/// Targets for Schnorr signature over ecGFp5.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SignatureTarget {
|
||||
pub s: BigUInt320Target,
|
||||
pub e: BigUInt320Target,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use plonky2::{
|
|||
},
|
||||
plonk::circuit_builder::CircuitBuilder,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
|
|
@ -35,7 +36,7 @@ use crate::{
|
|||
middleware::{EMPTY_HASH, EMPTY_VALUE, F, HASH_SIZE},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct MerkleClaimAndProofTarget {
|
||||
pub(crate) max_depth: usize,
|
||||
// `enabled` determines if the merkleproof verification is enabled
|
||||
|
|
@ -194,6 +195,7 @@ impl MerkleClaimAndProofTarget {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct MerkleProofExistenceTarget {
|
||||
max_depth: usize,
|
||||
// `enabled` determines if the merkleproof verification is enabled
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ impl MerkleTree {
|
|||
}
|
||||
|
||||
/// returns an iterator over the leaves of the tree
|
||||
pub fn iter(&self) -> Iter {
|
||||
pub fn iter(&self) -> Iter<'_> {
|
||||
Iter {
|
||||
state: vec![&self.root],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use plonky2::{
|
|||
proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget},
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
|
|
@ -38,6 +39,7 @@ use crate::{
|
|||
// TODO: This is a very simple wrapper over the signature verification implemented on
|
||||
// `SignatureTarget`. I think we can remove this and use it directly. Also we're not using the
|
||||
// `enabled` flag, so it should be straight-forward to remove this.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SignatureVerifyTarget {
|
||||
// `enabled` determines if the signature verification is enabled
|
||||
pub(crate) enabled: BoolTarget,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue