Skip to content

Commit b7ac54d

Browse files
authored
Add some top-level examples (#303)
The examples show: - Building a Signed Pod with different types of values - Building a MainPod - Input SignedPod to MainPod - Input MainPod to MainPod - Using MainPod or MockMainPod - Using custom predicates
1 parent 6249406 commit b7ac54d

File tree

7 files changed

+227
-44
lines changed

7 files changed

+227
-44
lines changed

.github/workflows/clippy.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ jobs:
1919
components: clippy
2020
- name: Check lints with clippy
2121
run: cargo clippy
22+
- name: Check lints with clippy (examples)
23+
run: cargo clippy --examples

examples/main_pod_points.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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(&params);
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(&params);
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, &params, &[])?.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(&params, 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, &params).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(&params, 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, &params).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(&params, 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, &params).unwrap();
155+
println!("# pod_alice_over_9000\n:{}", pod_alice_over_9000);
156+
pod_alice_over_9000.pod.verify().unwrap();
157+
158+
Ok(())
159+
}

examples/signed_pod.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//! Simple example of building a signed pod and verifying it
2+
//!
3+
//! Run: `cargo run --release --example signed_pod`
4+
use std::collections::HashSet;
5+
6+
use pod2::{
7+
backends::plonky2::{primitives::ec::schnorr::SecretKey, signedpod::Signer},
8+
frontend::SignedPodBuilder,
9+
middleware::{containers::Set, Params, Value},
10+
};
11+
12+
fn main() -> Result<(), Box<dyn std::error::Error>> {
13+
let params = Params::default();
14+
15+
// Create a schnorr key pair to sign the pod
16+
let sk = SecretKey::new_rand();
17+
let pk = sk.public_key();
18+
println!("Public key: {:?}\n", pk);
19+
20+
let mut signer = Signer(sk);
21+
22+
// Build the signed pod
23+
let mut builder = SignedPodBuilder::new(&params);
24+
// The values can be String, i64, bool, Array, Set, Dictionary, ...
25+
builder.insert("name", "Alice");
26+
builder.insert("lucky_number", 42);
27+
builder.insert("human", true);
28+
let friends_set: HashSet<Value> = ["Bob", "Charlie", "Dave"]
29+
.into_iter()
30+
.map(Value::from)
31+
.collect();
32+
builder.insert(
33+
"friends",
34+
Set::new(params.max_merkle_proofs_containers, friends_set)?,
35+
);
36+
37+
// Sign the pod and verify it
38+
let pod = builder.sign(&mut signer)?;
39+
pod.verify()?;
40+
41+
println!("{}", pod);
42+
43+
Ok(())
44+
}

src/examples/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ impl EthDosHelper {
155155

156156
let mut pod = MainPodBuilder::new(&self.params, &self.vd_set);
157157
pod.add_signed_pod(int_attestation);
158-
pod.add_main_pod(eth_dos_src_to_int_pod.clone());
158+
pod.add_recursive_pod(eth_dos_src_to_int_pod.clone());
159159

160160
let eth_dos_int_to_dst = eth_dos_src_to_int_pod
161161
.pod

src/frontend/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub struct MainPodBuilder {
120120
pub params: Params,
121121
pub vd_set: VDSet,
122122
pub input_signed_pods: Vec<SignedPod>,
123-
pub input_main_pods: Vec<MainPod>,
123+
pub input_recursive_pods: Vec<MainPod>,
124124
pub statements: Vec<Statement>,
125125
pub operations: Vec<Operation>,
126126
pub public_statements: Vec<Statement>,
@@ -139,7 +139,7 @@ impl fmt::Display for MainPodBuilder {
139139
writeln!(f, " - {}", in_pod.id())?;
140140
}
141141
writeln!(f, " input_main_pods:")?;
142-
for in_pod in &self.input_main_pods {
142+
for in_pod in &self.input_recursive_pods {
143143
writeln!(f, " - {}", in_pod.id())?;
144144
}
145145
writeln!(f, " statements:")?;
@@ -158,7 +158,7 @@ impl MainPodBuilder {
158158
params: params.clone(),
159159
vd_set: vd_set.clone(),
160160
input_signed_pods: Vec::new(),
161-
input_main_pods: Vec::new(),
161+
input_recursive_pods: Vec::new(),
162162
statements: Vec::new(),
163163
operations: Vec::new(),
164164
public_statements: Vec::new(),
@@ -169,8 +169,8 @@ impl MainPodBuilder {
169169
pub fn add_signed_pod(&mut self, pod: &SignedPod) {
170170
self.input_signed_pods.push(pod.clone());
171171
}
172-
pub fn add_main_pod(&mut self, pod: MainPod) {
173-
self.input_main_pods.push(pod);
172+
pub fn add_recursive_pod(&mut self, pod: MainPod) {
173+
self.input_recursive_pods.push(pod);
174174
}
175175
pub fn insert(&mut self, public: bool, st_op: (Statement, Operation)) {
176176
// TODO: Do error handling instead of panic
@@ -538,7 +538,7 @@ impl MainPodBuilder {
538538
self.public_statements.push(st.clone());
539539
}
540540

541-
pub fn prove<P: PodProver>(&self, prover: &mut P, params: &Params) -> Result<MainPod> {
541+
pub fn prove(&self, prover: &dyn PodProver, params: &Params) -> Result<MainPod> {
542542
let compiler = MainPodCompiler::new(&self.params);
543543
let inputs = MainPodCompilerInputs {
544544
// signed_pods: &self.input_signed_pods,
@@ -557,7 +557,7 @@ impl MainPodBuilder {
557557
.map(|p| p.pod.as_ref())
558558
.collect_vec(),
559559
recursive_pods: &self
560-
.input_main_pods
560+
.input_recursive_pods
561561
.iter()
562562
.map(|p| p.pod.as_ref())
563563
.collect_vec(),

src/frontend/operation.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ impl fmt::Display for OperationArg {
4545
}
4646
}
4747

48-
impl From<Value> for OperationArg {
49-
fn from(v: Value) -> Self {
50-
Self::Literal(v)
48+
impl<V: Into<Value>> From<V> for OperationArg {
49+
fn from(value: V) -> Self {
50+
Self::Literal(value.into())
5151
}
5252
}
5353

@@ -57,24 +57,6 @@ impl From<&Value> for OperationArg {
5757
}
5858
}
5959

60-
impl From<&str> for OperationArg {
61-
fn from(s: &str) -> Self {
62-
Self::Literal(Value::from(s))
63-
}
64-
}
65-
66-
impl From<i64> for OperationArg {
67-
fn from(v: i64) -> Self {
68-
Self::Literal(Value::from(v))
69-
}
70-
}
71-
72-
impl From<bool> for OperationArg {
73-
fn from(b: bool) -> Self {
74-
Self::Literal(Value::from(b))
75-
}
76-
}
77-
7860
impl From<(&SignedPod, &str)> for OperationArg {
7961
fn from((pod, key): (&SignedPod, &str)) -> Self {
8062
// TODO: TryFrom.

src/middleware/basetypes.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,7 @@ impl From<Hash> for RawValue {
121121

122122
impl fmt::Display for RawValue {
123123
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124-
if self.0[2].is_zero() && self.0[3].is_zero() {
125-
// Assume this is an integer
126-
let (l0, l1) = (self.0[0].to_canonical_u64(), self.0[1].to_canonical_u64());
127-
assert!(l0 < (1 << 32));
128-
assert!(l1 < (1 << 32));
129-
write!(f, "{}", l0 + l1 * (1 << 32))
130-
} else {
131-
// Assume this is a hash
132-
Hash(self.0).fmt(f)
133-
}
124+
Hash(self.0).fmt(f)
134125
}
135126
}
136127

@@ -206,14 +197,19 @@ impl Ord for Hash {
206197
}
207198
}
208199

209-
// TODO: In alternate mode, don't shorten the hash
210200
impl fmt::Display for Hash {
211201
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212-
let v0 = self.0[0].to_canonical_u64();
213-
for i in 0..HASH_SIZE {
214-
write!(f, "{:02x}", (v0 >> (i * 8)) & 0xff)?;
202+
if f.alternate() {
203+
write!(f, "0x{}", self.encode_hex::<String>())
204+
} else {
205+
// display first hex digit in big endian
206+
write!(f, "0x")?;
207+
let v3 = self.0[3].to_canonical_u64();
208+
for i in 0..4 {
209+
write!(f, "{:02x}", (v3 >> ((7 - i) * 8)) & 0xff)?;
210+
}
211+
write!(f, "…")
215212
}
216-
write!(f, "…")
217213
}
218214
}
219215

0 commit comments

Comments
 (0)