diff --git a/book/src/examples.md b/book/src/examples.md index 4ec5579..bed4a23 100644 --- a/book/src/examples.md +++ b/book/src/examples.md @@ -99,30 +99,40 @@ statement loan_check(receiver: string): A Good Boy Pod exposes one custom statement with one custom deduction rule. ``` -statement good_boy(receiver: PubKey, good_boy_issuers: MerkleTree): +statement is_good_boy(user: PubKey, good_boy_issuers: MerkleTree): - OR(): - - AND(pod: Pod): - # A good boy issuer is my friend + - AND(pod: Pod, age: Int): - eq(pod.type, SIGNATURE) - contains(good_boy_issuers, pod.signer) - - eq(pod.friend, receiver) + # A good boy issuer says this user is a good boy + - eq(pod.user, user) + - eq(pod.age, age) +``` + +A Friend Pod exposes one custom statement with one custom deduction rule. + +``` +statement is_friend(good_boy: PubKey, friend: PubKey, good_boy_issuers: MerkleTree): + - OR(): + - AND(friend_pod: Pod): + - eq(pod.type, SIGNATURE) + # The issuer is a good boy + - is_good_boy(good_boy, good_boy_issuers) + # A good boy says this is their friend + - eq(pod.signer, good_boy) + - eq(pod.friend, friend) ``` A Great Boy Pod exposes (in addition to the above) one new custom statement with one custom deduction rule. ``` -statement great_boy(receiver: PubKey, good_boy_issuers: MerkleTree): +statement is_great_boy(great_boy: PubKey, good_boy_issuers: MerkleTree): - OR(): - AND(friend_pod_0: Pod, friend_pod_1: Pod): - # good boy 0 is my friend - - eq(friend_pod_0.type, SIGNATURE) - - good_boy(friend_pod_0.signer, good_boy_issuers) - - eq(friend_pod_0.friend, receiver) - # good boy 1 is my friend - - eq(friend_pod_1.type, SIGNATURE) - - good_boy(friend_pod_1.signer, good_boy_issuers) - - eq(friend_pod_1.friend, receiver) + # Two good boys consider this user their friend + - is_friend(friend_pod_0.signer, great_boy) + - is_friend(friend_pod_1.signer, great_boy) # good boy 0 != good boy 1 - neq(friend_pod_0.signer, friend_pod_1.signer) ``` diff --git a/src/backends/mock_main.rs b/src/backends/mock_main.rs index b670547..cdbab22 100644 --- a/src/backends/mock_main.rs +++ b/src/backends/mock_main.rs @@ -486,14 +486,14 @@ impl MainPod for MockMainPod { pub mod tests { use super::*; use crate::backends::mock_signed::MockSigner; - use crate::frontend; + use crate::examples::{great_boy_pod_full_flow, zu_kyc_pod_builder, zu_kyc_sign_pod_builders}; use crate::middleware; #[test] - fn test_mock_main_0() { + fn test_mock_main_zu_kyc() { let params = middleware::Params::default(); - let (gov_id_builder, pay_stub_builder) = frontend::tests::zu_kyc_sign_pod_builders(¶ms); + let (gov_id_builder, pay_stub_builder) = zu_kyc_sign_pod_builders(¶ms); let mut signer = MockSigner { pk: "ZooGov".into(), }; @@ -502,7 +502,7 @@ pub mod tests { pk: "ZooDeel".into(), }; let pay_stub_pod = pay_stub_builder.sign(&mut signer).unwrap(); - let kyc_builder = frontend::tests::zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod); + let kyc_builder = zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod); let mut prover = MockProver {}; let kyc_pod = kyc_builder.prove(&mut prover).unwrap(); @@ -514,4 +514,21 @@ pub mod tests { // println!("id: {}", pod.id()); // println!("pub_statements: {:?}", pod.pub_statements()); } + + #[test] + fn test_mock_main_great_boy() { + let great_boy_builder = great_boy_pod_full_flow(); + + let mut prover = MockProver {}; + let great_boy_pod = great_boy_builder.prove(&mut prover).unwrap(); + let pod = great_boy_pod + .pod + .into_any() + .downcast::() + .unwrap(); + + println!("{}", pod); + + assert_eq!(pod.verify(), true); + } } diff --git a/src/examples.rs b/src/examples.rs new file mode 100644 index 0000000..0105ae3 --- /dev/null +++ b/src/examples.rs @@ -0,0 +1,194 @@ +use crate::frontend::{MainPodBuilder, MerkleTree, SignedPod, SignedPodBuilder, Value}; +use crate::middleware::{Params, PodType, KEY_SIGNER, KEY_TYPE}; +use crate::op; + +// ZuKYC + +pub fn zu_kyc_sign_pod_builders(params: &Params) -> (SignedPodBuilder, SignedPodBuilder) { + let mut gov_id = SignedPodBuilder::new(params); + gov_id.insert("idNumber", "4242424242"); + gov_id.insert("dateOfBirth", 1169909384); + gov_id.insert("socialSecurityNumber", "G2121210"); + + let mut pay_stub = SignedPodBuilder::new(params); + pay_stub.insert("socialSecurityNumber", "G2121210"); + pay_stub.insert("startDate", 1706367566); + + (gov_id, pay_stub) +} + +pub fn zu_kyc_pod_builder( + params: &Params, + gov_id: &SignedPod, + pay_stub: &SignedPod, +) -> MainPodBuilder { + let sanction_list = Value::MerkleTree(MerkleTree { root: 1 }); + let now_minus_18y: i64 = 1169909388; + let now_minus_1y: i64 = 1706367566; + + let mut kyc = MainPodBuilder::new(params); + kyc.add_signed_pod(&gov_id); + kyc.add_signed_pod(&pay_stub); + kyc.pub_op(op!(not_contains, &sanction_list, (gov_id, "idNumber"))); + kyc.pub_op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y)); + kyc.pub_op(op!( + eq, + (gov_id, "socialSecurityNumber"), + (pay_stub, "socialSecurityNumber") + )); + kyc.pub_op(op!(eq, (pay_stub, "startDate"), now_minus_1y)); + + kyc +} + +// GreatBoy + +pub fn good_boy_sign_pod_builder(params: &Params, user: &str, age: i64) -> SignedPodBuilder { + let mut good_boy = SignedPodBuilder::new(params); + good_boy.insert("user", user); + good_boy.insert("age", age); + + good_boy +} + +pub fn friend_sign_pod_builder(params: &Params, friend: &str) -> SignedPodBuilder { + let mut friend_pod = SignedPodBuilder::new(params); + friend_pod.insert("friend", friend); + + friend_pod +} + +pub fn great_boy_pod_builder( + params: &Params, + good_boy_pods: [&SignedPod; 4], + friend_pods: [&SignedPod; 2], + good_boy_issuers: &Value, + receiver: &str, +) -> MainPodBuilder { + // Attestment chain (issuer -> good boy -> great boy): + // issuer 0 -> good_boy_pods[0] => good boy 0 + // issuer 1 -> good_boy_pods[1] => good boy 0 + // issuer 2 -> good_boy_pods[2] => good boy 1 + // issuer 3 -> good_boy_pods[3] => good boy 1 + // good boy 0 -> friend_pods[0] => receiver + // good boy 1 -> friend_pods[1] => receiver + + let mut great_boy = MainPodBuilder::new(params); + for i in 0..4 { + great_boy.add_signed_pod(&good_boy_pods[i]); + } + for i in 0..2 { + great_boy.add_signed_pod(&friend_pods[i]); + } + + for good_boy_idx in 0..2 { + // Type check + great_boy.pub_op(op!( + eq, + (friend_pods[good_boy_idx], KEY_TYPE), + PodType::MockSigned as i64 + )); + for issuer_idx in 0..2 { + // Type check + great_boy.pub_op(op!( + eq, + (good_boy_pods[good_boy_idx * 2 + issuer_idx], KEY_TYPE), + PodType::MockSigned as i64 + )); + // Each good boy POD comes from a valid issuer + great_boy.pub_op(op!( + contains, + good_boy_issuers, + (good_boy_pods[good_boy_idx * 2 + issuer_idx], KEY_SIGNER) + )); + // Each good boy has 2 good boy pods + great_boy.pub_op(op!( + eq, + (good_boy_pods[good_boy_idx * 2 + issuer_idx], "user"), + (friend_pods[good_boy_idx], KEY_SIGNER) + )); + } + // The good boy PODs from each good boy have different issuers + great_boy.pub_op(op!( + ne, + (good_boy_pods[good_boy_idx * 2 + 0], KEY_SIGNER), + (good_boy_pods[good_boy_idx * 2 + 1], KEY_SIGNER) + )); + // Each good boy is receivers' friend + great_boy.pub_op(op!(eq, (friend_pods[good_boy_idx], "friend"), receiver)); + } + // The two good boys are different + great_boy.pub_op(op!( + ne, + (friend_pods[0], KEY_SIGNER), + (friend_pods[1], KEY_SIGNER) + )); + + great_boy +} + +pub fn great_boy_pod_full_flow() -> MainPodBuilder { + use crate::backends::mock_signed::MockSigner; + + let params = Params { + max_input_signed_pods: 6, + max_statements: 100, + max_public_statements: 50, + ..Default::default() + }; + + let good_boy_issuers = ["Giggles", "Macrosoft", "FaeBook"]; + let mut giggles_signer = MockSigner { + pk: good_boy_issuers[0].into(), + }; + let mut macrosoft_signer = MockSigner { + pk: good_boy_issuers[1].into(), + }; + let mut faebook_signer = MockSigner { + pk: good_boy_issuers[2].into(), + }; + let bob = "Bob"; + let charlie = "Charlie"; + let alice = "Alice"; + let mut bob_signer = MockSigner { pk: bob.into() }; + let mut charlie_signer = MockSigner { pk: charlie.into() }; + + // Bob receives two good_boy pods from Giggles and Macrosoft. + + let bob = "Bob"; + let mut bob_good_boys = Vec::new(); + + let good_boy = good_boy_sign_pod_builder(¶ms, &bob, 36); + bob_good_boys.push(good_boy.sign(&mut giggles_signer).unwrap()); + bob_good_boys.push(good_boy.sign(&mut macrosoft_signer).unwrap()); + + // Charlie receives two good_boy pods from Macrosoft and Faebook + + let charlie = "Charlie"; + let mut charlie_good_boys = Vec::new(); + + let good_boy = good_boy_sign_pod_builder(¶ms, &charlie, 27); + charlie_good_boys.push(good_boy.sign(&mut macrosoft_signer).unwrap()); + charlie_good_boys.push(good_boy.sign(&mut faebook_signer).unwrap()); + + // Bob and Charlie send Alice a Friend POD + + let mut alice_friend_pods = Vec::new(); + let friend = friend_sign_pod_builder(¶ms, &alice); + alice_friend_pods.push(friend.sign(&mut bob_signer).unwrap()); + alice_friend_pods.push(friend.sign(&mut charlie_signer).unwrap()); + + let good_boy_issuers_mt = Value::MerkleTree(MerkleTree { root: 33 }); + great_boy_pod_builder( + ¶ms, + [ + &bob_good_boys[0], + &bob_good_boys[1], + &charlie_good_boys[0], + &charlie_good_boys[1], + ], + [&alice_friend_pods[0], &alice_friend_pods[1]], + &good_boy_issuers_mt, + alice, + ) +} diff --git a/src/frontend.rs b/src/frontend.rs index b82002f..cae15df 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -545,63 +545,44 @@ impl MainPodCompiler { // TODO fn fmt_signed_pod_builder // TODO fn fmt_main_pod +#[macro_use] +pub mod build_utils { + #[macro_export] + macro_rules! op_args { + ($($arg:expr),+) => {vec![$(crate::frontend::OperationArg::from($arg)),*]} + } + + #[macro_export] + macro_rules! op { + (eq, $($arg:expr),+) => { crate::frontend::Operation( + crate::middleware::NativeOperation::EqualFromEntries, + crate::op_args!($($arg),*)) }; + (ne, $($arg:expr),+) => { crate::frontend::Operation( + crate::middleware::NativeOperation::NotEqualFromEntries, + crate::op_args!($($arg),*)) }; + (gt, $($arg:expr),+) => { crate::frontend::Operation( + crate::middleware::NativeOperation::GtFromEntries, + crate::op_args!($($arg),*)) }; + (lt, $($arg:expr),+) => { crate::frontend::Operation( + crate::middleware::NativeOperation::LtFromEntries, + crate::op_args!($($arg),*)) }; + (contains, $($arg:expr),+) => { crate::frontend::Operation( + crate::middleware::NativeOperation::ContainsFromEntries, + crate::op_args!($($arg),*)) }; + (not_contains, $($arg:expr),+) => { crate::frontend::Operation( + crate::middleware::NativeOperation::NotContainsFromEntries, + crate::op_args!($($arg),*)) }; + } +} + #[cfg(test)] pub mod tests { use super::*; use crate::backends::mock_signed::MockSigner; - - macro_rules! args { - ($($arg:expr),+) => {vec![$(OperationArg::from($arg)),*]} - } - - macro_rules! op { - (eq, $($arg:expr),+) => { Operation(NativeOperation::EqualFromEntries, args!($($arg),*)) }; - (ne, $($arg:expr),+) => { Operation(NativeOperation::NotEqualFromEntries, args!($($arg),*)) }; - (gt, $($arg:expr),+) => { Operation(NativeOperation::GtFromEntries, args!($($arg),*)) }; - (lt, $($arg:expr),+) => { Operation(NativeOperation::LtFromEntries, args!($($arg),*)) }; - (contains, $($arg:expr),+) => { Operation(NativeOperation::ContainsFromEntries, args!($($arg),*)) }; - (not_contains, $($arg:expr),+) => { Operation(NativeOperation::NotContainsFromEntries, args!($($arg),*)) }; - } - - pub fn zu_kyc_sign_pod_builders(params: &Params) -> (SignedPodBuilder, SignedPodBuilder) { - let mut gov_id = SignedPodBuilder::new(params); - gov_id.insert("idNumber", "4242424242"); - gov_id.insert("dateOfBirth", 1169909384); - gov_id.insert("socialSecurityNumber", "G2121210"); - - let mut pay_stub = SignedPodBuilder::new(params); - pay_stub.insert("socialSecurityNumber", "G2121210"); - pay_stub.insert("startDate", 1706367566); - - (gov_id, pay_stub) - } - - pub fn zu_kyc_pod_builder( - params: &Params, - gov_id: &SignedPod, - pay_stub: &SignedPod, - ) -> MainPodBuilder { - let sanction_list = Value::MerkleTree(MerkleTree { root: 1 }); - let now_minus_18y: i64 = 1169909388; - let now_minus_1y: i64 = 1706367566; - - let mut kyc = MainPodBuilder::new(¶ms); - kyc.add_signed_pod(&gov_id); - kyc.add_signed_pod(&pay_stub); - kyc.pub_op(op!(not_contains, &sanction_list, (gov_id, "idNumber"))); - kyc.pub_op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y)); - kyc.pub_op(op!( - eq, - (gov_id, "socialSecurityNumber"), - (pay_stub, "socialSecurityNumber") - )); - kyc.pub_op(op!(eq, (pay_stub, "startDate"), now_minus_1y)); - - kyc - } + use crate::examples::{great_boy_pod_full_flow, zu_kyc_pod_builder, zu_kyc_sign_pod_builders}; #[test] - fn test_front_0() -> Result<()> { + fn test_front_zu_kyc() -> Result<()> { let params = Params::default(); let (gov_id, pay_stub) = zu_kyc_sign_pod_builders(¶ms); @@ -626,4 +607,14 @@ pub mod tests { Ok(()) } + + #[test] + fn test_front_great_boy() -> Result<()> { + let great_boy = great_boy_pod_full_flow(); + println!("{}", great_boy); + + // TODO: prove kyc with MockProver and print it + + Ok(()) + } } diff --git a/src/lib.rs b/src/lib.rs index a092ae4..4bad04e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,6 @@ pub mod backends; pub mod frontend; pub mod merkletree; pub mod middleware; + +#[cfg(test)] +pub mod examples;