diff --git a/Cargo.toml b/Cargo.toml index 240b9e4..7e96497 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ strum = "0.26" strum_macros = "0.26" anyhow = "1.0.56" dyn-clone = "1.0.18" +log = "0.4" +env_logger = "0.11" # enabled by features: plonky2 = { git = "https://github.com/0xPolygonZero/plonky2", optional = true } diff --git a/src/backends/plonky2/mock_main/mod.rs b/src/backends/plonky2/mock_main/mod.rs index d91f725..aa08d53 100644 --- a/src/backends/plonky2/mock_main/mod.rs +++ b/src/backends/plonky2/mock_main/mod.rs @@ -1,5 +1,6 @@ use anyhow::{anyhow, Result}; use itertools::Itertools; +use log::error; use plonky2::hash::poseidon::PoseidonHash; use plonky2::plonk::config::Hasher; use std::any::Any; @@ -434,10 +435,22 @@ impl Pod for MockMainPod { self.operations[i] .deref(&self.statements[..input_statement_offset + i]) .unwrap() - .check(&self.params, &s.clone().try_into().unwrap()) + .check_and_log(&self.params, &s.clone().try_into().unwrap()) }) .collect::>>() .unwrap(); + if !ids_match { + error!("Verification failed: POD ID is incorrect."); + } + if !has_type_statement { + error!("Verification failed: POD does not have type statement."); + } + if !value_ofs_unique { + error!("Verification failed: Repeated ValueOf"); + } + if !statement_check.iter().all(|b| *b) { + error!("Verification failed: Statement did not check.") + } ids_match && has_type_statement && value_ofs_unique & statement_check.into_iter().all(|b| b) } fn id(&self) -> PodId { diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 69a4236..df1b752 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -2,7 +2,9 @@ //! with Pods. use anyhow::{anyhow, Error, Result}; +use env_logger; use itertools::Itertools; +use log::error; use std::collections::HashMap; use std::convert::From; use std::{fmt, hash as h}; @@ -1152,4 +1154,87 @@ pub mod tests { println!("{}", builder); println!("{}", false_pod); } + + #[test] + #[should_panic] + fn test_incorrect_pod() { + // try to insert the same key multiple times + // right now this is not caught when you build the pod, + // but it is caught on verify + env_logger::init(); + + let params = Params::default(); + let mut builder = MainPodBuilder::new(¶ms); + builder.insert(( + Statement( + Predicate::Native(NativePredicate::ValueOf), + vec![ + StatementArg::Key(AnchoredKey(Origin(PodClass::Main, SELF), "a".into())), + StatementArg::Literal(Value::Int(3)), + ], + ), + Operation(OperationType::Native(NativeOperation::NewEntry), vec![]), + )); + builder.insert(( + Statement( + Predicate::Native(NativePredicate::ValueOf), + vec![ + StatementArg::Key(AnchoredKey(Origin(PodClass::Main, SELF), "a".into())), + StatementArg::Literal(Value::Int(28)), + ], + ), + Operation(OperationType::Native(NativeOperation::NewEntry), vec![]), + )); + + let mut prover = MockProver {}; + let pod = builder.prove(&mut prover, ¶ms).unwrap(); + pod.pod.verify(); + + // try to insert a statement that doesn't follow from the operation + // right now the mock prover catches this when it calls compile() + let params = Params::default(); + let mut builder = MainPodBuilder::new(¶ms); + let self_a = AnchoredKey(Origin(PodClass::Main, SELF), "a".into()); + let self_b = AnchoredKey(Origin(PodClass::Main, SELF), "b".into()); + let value_of_a = Statement( + Predicate::Native(NativePredicate::ValueOf), + vec![ + StatementArg::Key(AnchoredKey(Origin(PodClass::Main, SELF), "a".into())), + StatementArg::Literal(Value::Int(3)), + ], + ); + let value_of_b = Statement( + Predicate::Native(NativePredicate::ValueOf), + vec![ + StatementArg::Key(AnchoredKey(Origin(PodClass::Main, SELF), "b".into())), + StatementArg::Literal(Value::Int(27)), + ], + ); + + builder.insert(( + value_of_a.clone(), + Operation(OperationType::Native(NativeOperation::NewEntry), vec![]), + )); + builder.insert(( + value_of_b.clone(), + Operation(OperationType::Native(NativeOperation::NewEntry), vec![]), + )); + builder.insert(( + Statement( + Predicate::Native(NativePredicate::Equal), + vec![StatementArg::Key(self_a), StatementArg::Key(self_b)], + ), + Operation( + OperationType::Native(NativeOperation::EqualFromEntries), + vec![ + OperationArg::Statement(value_of_a), + OperationArg::Statement(value_of_b), + ], + ), + )); + + let mut prover = MockProver {}; + let pod = builder.prove(&mut prover, ¶ms).unwrap(); + pod.pod.verify(); + } } diff --git a/src/middleware/operation.rs b/src/middleware/operation.rs index cdfcd02..743e01e 100644 --- a/src/middleware/operation.rs +++ b/src/middleware/operation.rs @@ -1,6 +1,7 @@ use std::fmt; use anyhow::{anyhow, Result}; +use log::error; use super::{CustomPredicateRef, NativePredicate, Statement, StatementArg}; use crate::middleware::{AnchoredKey, Params, Predicate, Value, SELF}; @@ -308,6 +309,15 @@ impl Operation { .map(|(pred, st_args)| Statement::from_args(pred, st_args)); x.transpose() } + /// Checks the given operation against a statement, and prints information if the check does not pass + pub fn check_and_log(&self, params: &Params, output_statement: &Statement) -> Result { + let valid: bool = self.check(params, output_statement)?; + if !valid { + error!("Check failed on the following statement"); + error!("{}", output_statement); + } + Ok(valid) + } /// Checks the given operation against a statement. pub fn check(&self, _params: &Params, output_statement: &Statement) -> Result { use Statement::*;