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
This commit is contained in:
parent
6249406cb2
commit
b7ac54d972
7 changed files with 227 additions and 44 deletions
2
.github/workflows/clippy.yml
vendored
2
.github/workflows/clippy.yml
vendored
|
|
@ -19,3 +19,5 @@ jobs:
|
||||||
components: clippy
|
components: clippy
|
||||||
- name: Check lints with clippy
|
- name: Check lints with clippy
|
||||||
run: cargo clippy
|
run: cargo clippy
|
||||||
|
- name: Check lints with clippy (examples)
|
||||||
|
run: cargo clippy --examples
|
||||||
|
|
|
||||||
159
examples/main_pod_points.rs
Normal file
159
examples/main_pod_points.rs
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
//! 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>> {
|
||||||
|
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 mut 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(&mut 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(&mut 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(())
|
||||||
|
}
|
||||||
44
examples/signed_pod.rs
Normal file
44
examples/signed_pod.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
//! Simple example of building a signed pod and verifying it
|
||||||
|
//!
|
||||||
|
//! Run: `cargo run --release --example signed_pod`
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use pod2::{
|
||||||
|
backends::plonky2::{primitives::ec::schnorr::SecretKey, signedpod::Signer},
|
||||||
|
frontend::SignedPodBuilder,
|
||||||
|
middleware::{containers::Set, Params, Value},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let params = Params::default();
|
||||||
|
|
||||||
|
// Create a schnorr key pair to sign the pod
|
||||||
|
let sk = SecretKey::new_rand();
|
||||||
|
let pk = sk.public_key();
|
||||||
|
println!("Public key: {:?}\n", pk);
|
||||||
|
|
||||||
|
let mut signer = Signer(sk);
|
||||||
|
|
||||||
|
// Build the signed pod
|
||||||
|
let mut builder = SignedPodBuilder::new(¶ms);
|
||||||
|
// The values can be String, i64, bool, Array, Set, Dictionary, ...
|
||||||
|
builder.insert("name", "Alice");
|
||||||
|
builder.insert("lucky_number", 42);
|
||||||
|
builder.insert("human", true);
|
||||||
|
let friends_set: HashSet<Value> = ["Bob", "Charlie", "Dave"]
|
||||||
|
.into_iter()
|
||||||
|
.map(Value::from)
|
||||||
|
.collect();
|
||||||
|
builder.insert(
|
||||||
|
"friends",
|
||||||
|
Set::new(params.max_merkle_proofs_containers, friends_set)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sign the pod and verify it
|
||||||
|
let pod = builder.sign(&mut signer)?;
|
||||||
|
pod.verify()?;
|
||||||
|
|
||||||
|
println!("{}", pod);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -155,7 +155,7 @@ impl EthDosHelper {
|
||||||
|
|
||||||
let mut pod = MainPodBuilder::new(&self.params, &self.vd_set);
|
let mut pod = MainPodBuilder::new(&self.params, &self.vd_set);
|
||||||
pod.add_signed_pod(int_attestation);
|
pod.add_signed_pod(int_attestation);
|
||||||
pod.add_main_pod(eth_dos_src_to_int_pod.clone());
|
pod.add_recursive_pod(eth_dos_src_to_int_pod.clone());
|
||||||
|
|
||||||
let eth_dos_int_to_dst = eth_dos_src_to_int_pod
|
let eth_dos_int_to_dst = eth_dos_src_to_int_pod
|
||||||
.pod
|
.pod
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ pub struct MainPodBuilder {
|
||||||
pub params: Params,
|
pub params: Params,
|
||||||
pub vd_set: VDSet,
|
pub vd_set: VDSet,
|
||||||
pub input_signed_pods: Vec<SignedPod>,
|
pub input_signed_pods: Vec<SignedPod>,
|
||||||
pub input_main_pods: Vec<MainPod>,
|
pub input_recursive_pods: Vec<MainPod>,
|
||||||
pub statements: Vec<Statement>,
|
pub statements: Vec<Statement>,
|
||||||
pub operations: Vec<Operation>,
|
pub operations: Vec<Operation>,
|
||||||
pub public_statements: Vec<Statement>,
|
pub public_statements: Vec<Statement>,
|
||||||
|
|
@ -139,7 +139,7 @@ impl fmt::Display for MainPodBuilder {
|
||||||
writeln!(f, " - {}", in_pod.id())?;
|
writeln!(f, " - {}", in_pod.id())?;
|
||||||
}
|
}
|
||||||
writeln!(f, " input_main_pods:")?;
|
writeln!(f, " input_main_pods:")?;
|
||||||
for in_pod in &self.input_main_pods {
|
for in_pod in &self.input_recursive_pods {
|
||||||
writeln!(f, " - {}", in_pod.id())?;
|
writeln!(f, " - {}", in_pod.id())?;
|
||||||
}
|
}
|
||||||
writeln!(f, " statements:")?;
|
writeln!(f, " statements:")?;
|
||||||
|
|
@ -158,7 +158,7 @@ impl MainPodBuilder {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
vd_set: vd_set.clone(),
|
vd_set: vd_set.clone(),
|
||||||
input_signed_pods: Vec::new(),
|
input_signed_pods: Vec::new(),
|
||||||
input_main_pods: Vec::new(),
|
input_recursive_pods: Vec::new(),
|
||||||
statements: Vec::new(),
|
statements: Vec::new(),
|
||||||
operations: Vec::new(),
|
operations: Vec::new(),
|
||||||
public_statements: Vec::new(),
|
public_statements: Vec::new(),
|
||||||
|
|
@ -169,8 +169,8 @@ impl MainPodBuilder {
|
||||||
pub fn add_signed_pod(&mut self, pod: &SignedPod) {
|
pub fn add_signed_pod(&mut self, pod: &SignedPod) {
|
||||||
self.input_signed_pods.push(pod.clone());
|
self.input_signed_pods.push(pod.clone());
|
||||||
}
|
}
|
||||||
pub fn add_main_pod(&mut self, pod: MainPod) {
|
pub fn add_recursive_pod(&mut self, pod: MainPod) {
|
||||||
self.input_main_pods.push(pod);
|
self.input_recursive_pods.push(pod);
|
||||||
}
|
}
|
||||||
pub fn insert(&mut self, public: bool, st_op: (Statement, Operation)) {
|
pub fn insert(&mut self, public: bool, st_op: (Statement, Operation)) {
|
||||||
// TODO: Do error handling instead of panic
|
// TODO: Do error handling instead of panic
|
||||||
|
|
@ -538,7 +538,7 @@ impl MainPodBuilder {
|
||||||
self.public_statements.push(st.clone());
|
self.public_statements.push(st.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prove<P: PodProver>(&self, prover: &mut P, params: &Params) -> Result<MainPod> {
|
pub fn prove(&self, prover: &dyn PodProver, params: &Params) -> Result<MainPod> {
|
||||||
let compiler = MainPodCompiler::new(&self.params);
|
let compiler = MainPodCompiler::new(&self.params);
|
||||||
let inputs = MainPodCompilerInputs {
|
let inputs = MainPodCompilerInputs {
|
||||||
// signed_pods: &self.input_signed_pods,
|
// signed_pods: &self.input_signed_pods,
|
||||||
|
|
@ -557,7 +557,7 @@ impl MainPodBuilder {
|
||||||
.map(|p| p.pod.as_ref())
|
.map(|p| p.pod.as_ref())
|
||||||
.collect_vec(),
|
.collect_vec(),
|
||||||
recursive_pods: &self
|
recursive_pods: &self
|
||||||
.input_main_pods
|
.input_recursive_pods
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.pod.as_ref())
|
.map(|p| p.pod.as_ref())
|
||||||
.collect_vec(),
|
.collect_vec(),
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,9 @@ impl fmt::Display for OperationArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Value> for OperationArg {
|
impl<V: Into<Value>> From<V> for OperationArg {
|
||||||
fn from(v: Value) -> Self {
|
fn from(value: V) -> Self {
|
||||||
Self::Literal(v)
|
Self::Literal(value.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,24 +57,6 @@ impl From<&Value> for OperationArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for OperationArg {
|
|
||||||
fn from(s: &str) -> Self {
|
|
||||||
Self::Literal(Value::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i64> for OperationArg {
|
|
||||||
fn from(v: i64) -> Self {
|
|
||||||
Self::Literal(Value::from(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<bool> for OperationArg {
|
|
||||||
fn from(b: bool) -> Self {
|
|
||||||
Self::Literal(Value::from(b))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&SignedPod, &str)> for OperationArg {
|
impl From<(&SignedPod, &str)> for OperationArg {
|
||||||
fn from((pod, key): (&SignedPod, &str)) -> Self {
|
fn from((pod, key): (&SignedPod, &str)) -> Self {
|
||||||
// TODO: TryFrom.
|
// TODO: TryFrom.
|
||||||
|
|
|
||||||
|
|
@ -121,16 +121,7 @@ impl From<Hash> for RawValue {
|
||||||
|
|
||||||
impl fmt::Display for RawValue {
|
impl fmt::Display for RawValue {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if self.0[2].is_zero() && self.0[3].is_zero() {
|
Hash(self.0).fmt(f)
|
||||||
// Assume this is an integer
|
|
||||||
let (l0, l1) = (self.0[0].to_canonical_u64(), self.0[1].to_canonical_u64());
|
|
||||||
assert!(l0 < (1 << 32));
|
|
||||||
assert!(l1 < (1 << 32));
|
|
||||||
write!(f, "{}", l0 + l1 * (1 << 32))
|
|
||||||
} else {
|
|
||||||
// Assume this is a hash
|
|
||||||
Hash(self.0).fmt(f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,14 +197,19 @@ impl Ord for Hash {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: In alternate mode, don't shorten the hash
|
|
||||||
impl fmt::Display for Hash {
|
impl fmt::Display for Hash {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let v0 = self.0[0].to_canonical_u64();
|
if f.alternate() {
|
||||||
for i in 0..HASH_SIZE {
|
write!(f, "0x{}", self.encode_hex::<String>())
|
||||||
write!(f, "{:02x}", (v0 >> (i * 8)) & 0xff)?;
|
} else {
|
||||||
|
// display first hex digit in big endian
|
||||||
|
write!(f, "0x")?;
|
||||||
|
let v3 = self.0[3].to_canonical_u64();
|
||||||
|
for i in 0..4 {
|
||||||
|
write!(f, "{:02x}", (v3 >> ((7 - i) * 8)) & 0xff)?;
|
||||||
|
}
|
||||||
|
write!(f, "…")
|
||||||
}
|
}
|
||||||
write!(f, "…")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue