- 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.
161 lines
6.4 KiB
Rust
161 lines
6.4 KiB
Rust
#![allow(clippy::uninlined_format_args)] // TODO: Remove this in another PR
|
|
//! Example of building main pods that verify signed pods and other main pods using custom
|
|
//! predicates
|
|
//!
|
|
//! The example follows a scenario where a game issues signed pods to players with the points
|
|
//! accumulated after finishing each game level. Then we build a custom predicate to prove that
|
|
//! the sum of points from level 1 and 2 for a player is over 9000.
|
|
//!
|
|
//! Run in real mode: `cargo run --release --example main_pod_points`
|
|
//! Run in mock mode: `cargo run --release --example main_pod_points -- --mock`
|
|
use std::env;
|
|
|
|
use pod2::{
|
|
backends::plonky2::{
|
|
basetypes::DEFAULT_VD_SET, mainpod::Prover, mock::mainpod::MockProver,
|
|
primitives::ec::schnorr::SecretKey, signedpod::Signer,
|
|
},
|
|
frontend::{MainPodBuilder, SignedPodBuilder},
|
|
lang::parse,
|
|
middleware::{Params, PodProver, PodType, VDSet, Value, KEY_SIGNER, KEY_TYPE},
|
|
op,
|
|
};
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
env_logger::init();
|
|
let args: Vec<String> = env::args().collect();
|
|
let mock = args.get(1).is_some_and(|arg1| arg1 == "--mock");
|
|
if mock {
|
|
println!("Using MockMainPod")
|
|
} else {
|
|
println!("Using MainPod")
|
|
}
|
|
|
|
let params = Params::default();
|
|
|
|
let mock_prover = MockProver {};
|
|
let real_prover = Prover {};
|
|
let (vd_set, prover): (_, &dyn PodProver) = if mock {
|
|
(&VDSet::new(8, &[])?, &mock_prover)
|
|
} else {
|
|
println!("Prebuilding circuits to calculate vd_set...");
|
|
let vd_set = &*DEFAULT_VD_SET;
|
|
println!("vd_set calculation complete");
|
|
(vd_set, &real_prover)
|
|
};
|
|
|
|
// Create a schnorr key pair to sign pods
|
|
let game_sk = SecretKey::new_rand();
|
|
let game_pk = game_sk.public_key();
|
|
|
|
let game_signer = Signer(game_sk);
|
|
|
|
// Build 2 signed pods where the game assigns points to a player that has completed a level.
|
|
let mut builder = SignedPodBuilder::new(¶ms);
|
|
builder.insert("player", "Alice");
|
|
builder.insert("level", 1);
|
|
builder.insert("points", 3512);
|
|
let pod_points_lvl_1 = builder.sign(&game_signer)?;
|
|
pod_points_lvl_1.verify()?;
|
|
println!("# pod_points_lvl_1:\n{}", pod_points_lvl_1);
|
|
|
|
let mut builder = SignedPodBuilder::new(¶ms);
|
|
builder.insert("player", "Alice");
|
|
builder.insert("level", 2);
|
|
builder.insert("points", 5771);
|
|
let pod_points_lvl_2 = builder.sign(&game_signer)?;
|
|
pod_points_lvl_2.verify()?;
|
|
println!("# pod_points_lvl_2:\n{}", pod_points_lvl_2);
|
|
|
|
// Build a MainPod to prove >9000 points from sum of level 1 and 2
|
|
|
|
// Declare the custom predicate
|
|
let input = format!(
|
|
r#"
|
|
points(player, level, points, private: points_pod) = AND(
|
|
Equal(?points_pod["{key_type}"], {pod_type})
|
|
Equal(?points_pod["{key_signer}"], {game_pk:#})
|
|
Equal(?points_pod["player"], ?player)
|
|
Equal(?points_pod["level"], ?level)
|
|
Equal(?points_pod["points"], ?points)
|
|
)
|
|
|
|
over_9000(player, private: points_lvl_1, points_lvl_2, points_total) = AND(
|
|
points(?player, 1, ?points_lvl_1)
|
|
points(?player, 2, ?points_lvl_2)
|
|
SumOf(?points_total, ?points_lvl_1, ?points_lvl_2)
|
|
Gt(?points_total, 9000)
|
|
)
|
|
"#,
|
|
key_type = KEY_TYPE,
|
|
key_signer = KEY_SIGNER,
|
|
pod_type = PodType::Signed as usize,
|
|
game_pk = Value::from(game_pk).raw(),
|
|
);
|
|
println!("# custom predicate batch:{}", input);
|
|
let batch = parse(&input, ¶ms, &[])?.custom_batch;
|
|
let points_pred = batch.predicate_ref_by_name("points").unwrap();
|
|
let over_9000_pred = batch.predicate_ref_by_name("over_9000").unwrap();
|
|
|
|
// Build a pod to prove the statement `points("Alice", 1, 3512)`
|
|
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
|
builder.add_signed_pod(&pod_points_lvl_1);
|
|
let st_type = builder.priv_op(op!(eq, (&pod_points_lvl_1, KEY_TYPE), PodType::Signed))?;
|
|
let st_signer = builder.priv_op(op!(eq, (&pod_points_lvl_1, KEY_SIGNER), game_pk))?;
|
|
let st_player = builder.priv_op(op!(eq, (&pod_points_lvl_1, "player"), "Alice"))?;
|
|
let st_level = builder.priv_op(op!(eq, (&pod_points_lvl_1, "level"), 1))?;
|
|
let st_points = builder.priv_op(op!(eq, (&pod_points_lvl_1, "points"), 3512))?;
|
|
let st_points_lvl_1 = builder.pub_op(op!(
|
|
custom,
|
|
points_pred.clone(),
|
|
st_type,
|
|
st_signer,
|
|
st_player,
|
|
st_level,
|
|
st_points
|
|
))?;
|
|
let pod_alice_lvl_1_points = builder.prove(prover, ¶ms).unwrap();
|
|
println!("# pod_alice_lvl_1_points\n:{}", pod_alice_lvl_1_points);
|
|
pod_alice_lvl_1_points.pod.verify().unwrap();
|
|
|
|
// Build a pod to prove the statement `points("Alice", 2, 5771)`
|
|
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
|
builder.add_signed_pod(&pod_points_lvl_2);
|
|
let st_type = builder.priv_op(op!(eq, (&pod_points_lvl_2, KEY_TYPE), PodType::Signed))?;
|
|
let st_signer = builder.priv_op(op!(eq, (&pod_points_lvl_2, KEY_SIGNER), game_pk))?;
|
|
let st_player = builder.priv_op(op!(eq, (&pod_points_lvl_2, "player"), "Alice"))?;
|
|
let st_level = builder.priv_op(op!(eq, (&pod_points_lvl_2, "level"), 2))?;
|
|
let st_points = builder.priv_op(op!(eq, (&pod_points_lvl_2, "points"), 5771))?;
|
|
let st_points_lvl_2 = builder.pub_op(op!(
|
|
custom,
|
|
points_pred,
|
|
st_type,
|
|
st_signer,
|
|
st_player,
|
|
st_level,
|
|
st_points
|
|
))?;
|
|
let pod_alice_lvl_2_points = builder.prove(prover, ¶ms).unwrap();
|
|
println!("# pod_alice_lvl_2_points\n:{}", pod_alice_lvl_2_points);
|
|
pod_alice_lvl_2_points.pod.verify().unwrap();
|
|
|
|
// Build a pod to prove the statement `over_9000("Alice")`
|
|
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
|
builder.add_recursive_pod(pod_alice_lvl_1_points);
|
|
builder.add_recursive_pod(pod_alice_lvl_2_points);
|
|
let st_points_total = builder.priv_op(op!(sum_of, 3512 + 5771, 3512, 5771))?;
|
|
let st_gt_9000 = builder.priv_op(op!(gt, 3512 + 5771, 9000))?;
|
|
let _st_over_9000 = builder.pub_op(op!(
|
|
custom,
|
|
over_9000_pred,
|
|
st_points_lvl_1,
|
|
st_points_lvl_2,
|
|
st_points_total,
|
|
st_gt_9000
|
|
));
|
|
let pod_alice_over_9000 = builder.prove(prover, ¶ms).unwrap();
|
|
println!("# pod_alice_over_9000\n:{}", pod_alice_over_9000);
|
|
pod_alice_over_9000.pod.verify().unwrap();
|
|
|
|
Ok(())
|
|
}
|