|
| 1 | +//! Example of building main pods that verify signed pods and other main pods using custom |
| 2 | +//! predicates |
| 3 | +//! |
| 4 | +//! The example follows a scenario where a game issues signed pods to players with the points |
| 5 | +//! accumulated after finishing each game level. Then we build a custom predicate to prove that |
| 6 | +//! the sum of points from level 1 and 2 for a player is over 9000. |
| 7 | +//! |
| 8 | +//! Run in real mode: `cargo run --release --example main_pod_points` |
| 9 | +//! Run in mock mode: `cargo run --release --example main_pod_points -- --mock` |
| 10 | +use std::env; |
| 11 | + |
| 12 | +use pod2::{ |
| 13 | + backends::plonky2::{ |
| 14 | + basetypes::DEFAULT_VD_SET, mainpod::Prover, mock::mainpod::MockProver, |
| 15 | + primitives::ec::schnorr::SecretKey, signedpod::Signer, |
| 16 | + }, |
| 17 | + frontend::{MainPodBuilder, SignedPodBuilder}, |
| 18 | + lang::parse, |
| 19 | + middleware::{Params, PodProver, PodType, VDSet, Value, KEY_SIGNER, KEY_TYPE}, |
| 20 | + op, |
| 21 | +}; |
| 22 | + |
| 23 | +fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 24 | + let args: Vec<String> = env::args().collect(); |
| 25 | + let mock = args.get(1).is_some_and(|arg1| arg1 == "--mock"); |
| 26 | + if mock { |
| 27 | + println!("Using MockMainPod") |
| 28 | + } else { |
| 29 | + println!("Using MainPod") |
| 30 | + } |
| 31 | + |
| 32 | + let params = Params::default(); |
| 33 | + |
| 34 | + let mock_prover = MockProver {}; |
| 35 | + let real_prover = Prover {}; |
| 36 | + let (vd_set, prover): (_, &dyn PodProver) = if mock { |
| 37 | + (&VDSet::new(8, &[])?, &mock_prover) |
| 38 | + } else { |
| 39 | + println!("Prebuilding circuits to calculate vd_set..."); |
| 40 | + let vd_set = &*DEFAULT_VD_SET; |
| 41 | + println!("vd_set calculation complete"); |
| 42 | + (vd_set, &real_prover) |
| 43 | + }; |
| 44 | + |
| 45 | + // Create a schnorr key pair to sign pods |
| 46 | + let game_sk = SecretKey::new_rand(); |
| 47 | + let game_pk = game_sk.public_key(); |
| 48 | + |
| 49 | + let mut game_signer = Signer(game_sk); |
| 50 | + |
| 51 | + // Build 2 signed pods where the game assigns points to a player that has completed a level. |
| 52 | + let mut builder = SignedPodBuilder::new(¶ms); |
| 53 | + builder.insert("player", "Alice"); |
| 54 | + builder.insert("level", 1); |
| 55 | + builder.insert("points", 3512); |
| 56 | + let pod_points_lvl_1 = builder.sign(&mut game_signer)?; |
| 57 | + pod_points_lvl_1.verify()?; |
| 58 | + println!("# pod_points_lvl_1:\n{}", pod_points_lvl_1); |
| 59 | + |
| 60 | + let mut builder = SignedPodBuilder::new(¶ms); |
| 61 | + builder.insert("player", "Alice"); |
| 62 | + builder.insert("level", 2); |
| 63 | + builder.insert("points", 5771); |
| 64 | + let pod_points_lvl_2 = builder.sign(&mut game_signer)?; |
| 65 | + pod_points_lvl_2.verify()?; |
| 66 | + println!("# pod_points_lvl_2:\n{}", pod_points_lvl_2); |
| 67 | + |
| 68 | + // Build a MainPod to prove >9000 points from sum of level 1 and 2 |
| 69 | + |
| 70 | + // Declare the custom predicate |
| 71 | + let input = format!( |
| 72 | + r#" |
| 73 | + points(player, level, points, private: points_pod) = AND( |
| 74 | + Equal(?points_pod["{key_type}"], {pod_type}) |
| 75 | + Equal(?points_pod["{key_signer}"], {game_pk:#}) |
| 76 | + Equal(?points_pod["player"], ?player) |
| 77 | + Equal(?points_pod["level"], ?level) |
| 78 | + Equal(?points_pod["points"], ?points) |
| 79 | + ) |
| 80 | +
|
| 81 | + over_9000(player, private: points_lvl_1, points_lvl_2, points_total) = AND( |
| 82 | + points(?player, 1, ?points_lvl_1) |
| 83 | + points(?player, 2, ?points_lvl_2) |
| 84 | + SumOf(?points_total, ?points_lvl_1, ?points_lvl_2) |
| 85 | + Gt(?points_total, 9000) |
| 86 | + ) |
| 87 | + "#, |
| 88 | + key_type = KEY_TYPE, |
| 89 | + key_signer = KEY_SIGNER, |
| 90 | + pod_type = PodType::Signed as usize, |
| 91 | + game_pk = Value::from(game_pk).raw(), |
| 92 | + ); |
| 93 | + println!("# custom predicate batch:{}", input); |
| 94 | + let batch = parse(&input, ¶ms, &[])?.custom_batch; |
| 95 | + let points_pred = batch.predicate_ref_by_name("points").unwrap(); |
| 96 | + let over_9000_pred = batch.predicate_ref_by_name("over_9000").unwrap(); |
| 97 | + |
| 98 | + // Build a pod to prove the statement `points("Alice", 1, 3512)` |
| 99 | + let mut builder = MainPodBuilder::new(¶ms, vd_set); |
| 100 | + builder.add_signed_pod(&pod_points_lvl_1); |
| 101 | + let st_type = builder.priv_op(op!(eq, (&pod_points_lvl_1, KEY_TYPE), PodType::Signed))?; |
| 102 | + let st_signer = builder.priv_op(op!(eq, (&pod_points_lvl_1, KEY_SIGNER), game_pk))?; |
| 103 | + let st_player = builder.priv_op(op!(eq, (&pod_points_lvl_1, "player"), "Alice"))?; |
| 104 | + let st_level = builder.priv_op(op!(eq, (&pod_points_lvl_1, "level"), 1))?; |
| 105 | + let st_points = builder.priv_op(op!(eq, (&pod_points_lvl_1, "points"), 3512))?; |
| 106 | + let st_points_lvl_1 = builder.pub_op(op!( |
| 107 | + custom, |
| 108 | + points_pred.clone(), |
| 109 | + st_type, |
| 110 | + st_signer, |
| 111 | + st_player, |
| 112 | + st_level, |
| 113 | + st_points |
| 114 | + ))?; |
| 115 | + let pod_alice_lvl_1_points = builder.prove(prover, ¶ms).unwrap(); |
| 116 | + println!("# pod_alice_lvl_1_points\n:{}", pod_alice_lvl_1_points); |
| 117 | + pod_alice_lvl_1_points.pod.verify().unwrap(); |
| 118 | + |
| 119 | + // Build a pod to prove the statement `points("Alice", 2, 5771)` |
| 120 | + let mut builder = MainPodBuilder::new(¶ms, vd_set); |
| 121 | + builder.add_signed_pod(&pod_points_lvl_2); |
| 122 | + let st_type = builder.priv_op(op!(eq, (&pod_points_lvl_2, KEY_TYPE), PodType::Signed))?; |
| 123 | + let st_signer = builder.priv_op(op!(eq, (&pod_points_lvl_2, KEY_SIGNER), game_pk))?; |
| 124 | + let st_player = builder.priv_op(op!(eq, (&pod_points_lvl_2, "player"), "Alice"))?; |
| 125 | + let st_level = builder.priv_op(op!(eq, (&pod_points_lvl_2, "level"), 2))?; |
| 126 | + let st_points = builder.priv_op(op!(eq, (&pod_points_lvl_2, "points"), 5771))?; |
| 127 | + let st_points_lvl_2 = builder.pub_op(op!( |
| 128 | + custom, |
| 129 | + points_pred, |
| 130 | + st_type, |
| 131 | + st_signer, |
| 132 | + st_player, |
| 133 | + st_level, |
| 134 | + st_points |
| 135 | + ))?; |
| 136 | + let pod_alice_lvl_2_points = builder.prove(prover, ¶ms).unwrap(); |
| 137 | + println!("# pod_alice_lvl_2_points\n:{}", pod_alice_lvl_2_points); |
| 138 | + pod_alice_lvl_2_points.pod.verify().unwrap(); |
| 139 | + |
| 140 | + // Build a pod to prove the statement `over_9000("Alice")` |
| 141 | + let mut builder = MainPodBuilder::new(¶ms, vd_set); |
| 142 | + builder.add_recursive_pod(pod_alice_lvl_1_points); |
| 143 | + builder.add_recursive_pod(pod_alice_lvl_2_points); |
| 144 | + let st_points_total = builder.priv_op(op!(sum_of, 3512 + 5771, 3512, 5771))?; |
| 145 | + let st_gt_9000 = builder.priv_op(op!(gt, 3512 + 5771, 9000))?; |
| 146 | + let _st_over_9000 = builder.pub_op(op!( |
| 147 | + custom, |
| 148 | + over_9000_pred, |
| 149 | + st_points_lvl_1, |
| 150 | + st_points_lvl_2, |
| 151 | + st_points_total, |
| 152 | + st_gt_9000 |
| 153 | + )); |
| 154 | + let pod_alice_over_9000 = builder.prove(prover, ¶ms).unwrap(); |
| 155 | + println!("# pod_alice_over_9000\n:{}", pod_alice_over_9000); |
| 156 | + pod_alice_over_9000.pod.verify().unwrap(); |
| 157 | + |
| 158 | + Ok(()) |
| 159 | +} |
0 commit comments