migrate from anyhow to thiserror (#197)
* migrate from anyhow to thiserror (#190). pending polish error msgs * Add backtrace and compartmentalize errors - Include backtraces in the errors we generate. To get this we can't just return a literal enum, because the backtrace requires a call. - Related to the previous point: add methods to create errors so we can include the backtrace conveniently without changing too much the syntax. So instead of `Err(Error::KeyNotFound(key))` (literal enum) it will be `Err(Error::key_not_found(key))` (method call) - Each error should be local to its scope, and each scope should only return its own error. - The merkle tree should return `TreeError` and not Error - The middleware should return `MiddlewareError` and not Error - With a global Error we can't easily include backend/frontend types in the error fields, so declare a `BackendError` and a `FrontendError` and follow the pattern from the previous point - The Pod traits should be able to return backend errors and will be used in the frontend; for that we change them to use trait object Error: `dyn std::error::Error` * fix error * apply suggestions from @arnaucube * rename XError and XResult to Error and Result * reorg signature * make frontend custom error more ergonomic * remove unnecessary feature --------- Co-authored-by: Eduard S. <eduardsanou@posteo.net>
This commit is contained in:
parent
58d3c6a236
commit
29545f03fc
31 changed files with 696 additions and 273 deletions
|
|
@ -17,6 +17,7 @@ dyn-clone = "1.0.18"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
|
thiserror = { version = "2.0.12" }
|
||||||
# enabled by features:
|
# enabled by features:
|
||||||
plonky2 = { git = "https://github.com/0xPolygonZero/plonky2", optional = true }
|
plonky2 = { git = "https://github.com/0xPolygonZero/plonky2", optional = true }
|
||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use std::{array, iter};
|
use std::{array, iter};
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
field::{
|
field::{
|
||||||
extension::Extendable,
|
extension::Extendable,
|
||||||
|
|
@ -19,6 +18,7 @@ use plonky2::{
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::D,
|
basetypes::D,
|
||||||
|
error::Result,
|
||||||
mainpod::{Operation, OperationArg, Statement},
|
mainpod::{Operation, OperationArg, Statement},
|
||||||
primitives::merkletree::MerkleClaimAndProofTarget,
|
primitives::merkletree::MerkleClaimAndProofTarget,
|
||||||
},
|
},
|
||||||
|
|
@ -75,7 +75,7 @@ impl StatementArgTarget {
|
||||||
params: &Params,
|
params: &Params,
|
||||||
arg: &StatementArg,
|
arg: &StatementArg,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
pw.set_target_arr(&self.elements, &arg.to_fields(params))
|
Ok(pw.set_target_arr(&self.elements, &arg.to_fields(params))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(first: ValueTarget, second: ValueTarget) -> Self {
|
fn new(first: ValueTarget, second: ValueTarget) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use anyhow::Result;
|
|
||||||
use itertools::zip_eq;
|
use itertools::zip_eq;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
hash::{hash_types::HashOutTarget, poseidon::PoseidonHash},
|
hash::{hash_types::HashOutTarget, poseidon::PoseidonHash},
|
||||||
|
|
@ -16,6 +15,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
signedpod::{SignedPodVerifyGadget, SignedPodVerifyTarget},
|
signedpod::{SignedPodVerifyGadget, SignedPodVerifyTarget},
|
||||||
},
|
},
|
||||||
|
error::Result,
|
||||||
mainpod,
|
mainpod,
|
||||||
primitives::merkletree::{
|
primitives::merkletree::{
|
||||||
MerkleClaimAndProof, MerkleClaimAndProofTarget, MerkleProofGadget,
|
MerkleClaimAndProof, MerkleClaimAndProofTarget, MerkleProofGadget,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
hash::hash_types::{HashOut, HashOutTarget},
|
hash::hash_types::{HashOut, HashOutTarget},
|
||||||
|
|
@ -15,6 +14,7 @@ use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::D,
|
basetypes::D,
|
||||||
circuits::common::{CircuitBuilderPod, StatementArgTarget, StatementTarget, ValueTarget},
|
circuits::common::{CircuitBuilderPod, StatementArgTarget, StatementTarget, ValueTarget},
|
||||||
|
error::Result,
|
||||||
primitives::{
|
primitives::{
|
||||||
merkletree::{
|
merkletree::{
|
||||||
MerkleClaimAndProof, MerkleProofExistenceGadget, MerkleProofExistenceTarget,
|
MerkleClaimAndProof, MerkleProofExistenceGadget, MerkleProofExistenceTarget,
|
||||||
|
|
|
||||||
93
src/backends/plonky2/error.rs
Normal file
93
src/backends/plonky2/error.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
use std::{backtrace::Backtrace, fmt::Debug};
|
||||||
|
|
||||||
|
use crate::middleware::{PodId, PodType, Value};
|
||||||
|
|
||||||
|
pub type Result<T, E = Error> = core::result::Result<T, E>;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum InnerError {
|
||||||
|
#[error("id does not match, expected {0}, found {1}")]
|
||||||
|
IdNotEqual(PodId, PodId),
|
||||||
|
#[error("type does not match, expected {0}, found {1}")]
|
||||||
|
TypeNotEqual(PodType, Value),
|
||||||
|
|
||||||
|
// POD related
|
||||||
|
#[error("invalid POD ID")]
|
||||||
|
PodIdInvalid,
|
||||||
|
#[error("verification failed: POD does not have type statement")]
|
||||||
|
NotTypeStatement,
|
||||||
|
#[error("repeated ValueOf")]
|
||||||
|
RepeatedValueOf,
|
||||||
|
#[error("Statement did not check")]
|
||||||
|
StatementNotCheck,
|
||||||
|
#[error("Key not found")]
|
||||||
|
KeyNotFound,
|
||||||
|
|
||||||
|
// Other
|
||||||
|
#[error("{0}")]
|
||||||
|
Custom(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Inner: {inner}\n{backtrace}")]
|
||||||
|
Inner {
|
||||||
|
inner: Box<InnerError>,
|
||||||
|
backtrace: Box<Backtrace>,
|
||||||
|
},
|
||||||
|
#[error("anyhow::Error: {0}")]
|
||||||
|
Anyhow(#[from] anyhow::Error),
|
||||||
|
#[error("Plonky2 proof failed to verify: {0}")]
|
||||||
|
Plonky2ProofFail(anyhow::Error),
|
||||||
|
#[error("base64::DecodeError: {0}")]
|
||||||
|
Base64Decode(#[from] base64::DecodeError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Tree(#[from] crate::backends::plonky2::primitives::merkletree::error::TreeError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Middleware(#[from] crate::middleware::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! new {
|
||||||
|
($inner:expr) => {
|
||||||
|
Error::Inner {
|
||||||
|
inner: Box::new($inner),
|
||||||
|
backtrace: Box::new(Backtrace::capture()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
use InnerError::*;
|
||||||
|
impl Error {
|
||||||
|
pub(crate) fn custom(s: String) -> Self {
|
||||||
|
new!(Custom(s))
|
||||||
|
}
|
||||||
|
pub(crate) fn plonky2_proof_fail(e: anyhow::Error) -> Self {
|
||||||
|
Self::Plonky2ProofFail(e)
|
||||||
|
}
|
||||||
|
pub(crate) fn key_not_found() -> Self {
|
||||||
|
new!(KeyNotFound)
|
||||||
|
}
|
||||||
|
pub(crate) fn statement_not_check() -> Self {
|
||||||
|
new!(StatementNotCheck)
|
||||||
|
}
|
||||||
|
pub(crate) fn repeated_value_of() -> Self {
|
||||||
|
new!(RepeatedValueOf)
|
||||||
|
}
|
||||||
|
pub(crate) fn not_type_statement() -> Self {
|
||||||
|
new!(NotTypeStatement)
|
||||||
|
}
|
||||||
|
pub(crate) fn pod_id_invalid() -> Self {
|
||||||
|
new!(PodIdInvalid)
|
||||||
|
}
|
||||||
|
pub(crate) fn id_not_equal(expected: PodId, found: PodId) -> Self {
|
||||||
|
new!(IdNotEqual(expected, found))
|
||||||
|
}
|
||||||
|
pub(crate) fn type_not_equal(expected: PodType, found: Value) -> Self {
|
||||||
|
new!(TypeNotEqual(expected, found))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@ pub mod operation;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
|
|
@ -19,12 +18,13 @@ use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::{C, D},
|
basetypes::{C, D},
|
||||||
circuits::mainpod::{MainPodVerifyCircuit, MainPodVerifyInput},
|
circuits::mainpod::{MainPodVerifyCircuit, MainPodVerifyInput},
|
||||||
|
error::{Error, Result},
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
signedpod::SignedPod,
|
signedpod::SignedPod,
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, AnchoredKey, Hash, MainPodInputs, NativeOperation, NonePod, OperationType, Params,
|
self, AnchoredKey, DynError, Hash, MainPodInputs, NativeOperation, NonePod, OperationType,
|
||||||
Pod, PodId, PodProver, PodType, StatementArg, ToFields, F, KEY_TYPE, SELF,
|
Params, Pod, PodId, PodProver, PodType, StatementArg, ToFields, F, KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -70,11 +70,11 @@ pub(crate) fn extract_merkle_proofs(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if merkle_proofs.len() > params.max_merkle_proofs {
|
if merkle_proofs.len() > params.max_merkle_proofs {
|
||||||
return Err(anyhow!(
|
return Err(Error::custom(format!(
|
||||||
"The number of required Merkle proofs ({}) exceeds the maximum number ({}).",
|
"The number of required Merkle proofs ({}) exceeds the maximum number ({}).",
|
||||||
merkle_proofs.len(),
|
merkle_proofs.len(),
|
||||||
params.max_merkle_proofs
|
params.max_merkle_proofs
|
||||||
));
|
)));
|
||||||
}
|
}
|
||||||
Ok(merkle_proofs)
|
Ok(merkle_proofs)
|
||||||
}
|
}
|
||||||
|
|
@ -90,10 +90,10 @@ fn find_op_arg(statements: &[Statement], op_arg: &middleware::Statement) -> Resu
|
||||||
(&middleware::Statement::try_from(s.clone()).ok()? == op_arg).then_some(i)
|
(&middleware::Statement::try_from(s.clone()).ok()? == op_arg).then_some(i)
|
||||||
})
|
})
|
||||||
.map(OperationArg::Index)
|
.map(OperationArg::Index)
|
||||||
.ok_or(anyhow!(
|
.ok_or(Error::custom(format!(
|
||||||
"Statement corresponding to op arg {} not found",
|
"Statement corresponding to op arg {} not found",
|
||||||
op_arg
|
op_arg
|
||||||
)),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,10 +109,10 @@ fn find_op_aux(
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(i, pf)| (pf.proof == *pf_arg).then_some(i))
|
.find_map(|(i, pf)| (pf.proof == *pf_arg).then_some(i))
|
||||||
.map(OperationAux::MerkleProofIndex)
|
.map(OperationAux::MerkleProofIndex)
|
||||||
.ok_or(anyhow!(
|
.ok_or(Error::custom(format!(
|
||||||
"Merkle proof corresponding to op arg {} not found",
|
"Merkle proof corresponding to op arg {} not found",
|
||||||
op_aux
|
op_aux
|
||||||
)),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,8 +279,8 @@ pub(crate) fn process_public_statements_operations(
|
||||||
|
|
||||||
pub struct Prover {}
|
pub struct Prover {}
|
||||||
|
|
||||||
impl PodProver for Prover {
|
impl Prover {
|
||||||
fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result<Box<dyn Pod>> {
|
fn _prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result<MainPod> {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
let main_pod = MainPodVerifyCircuit {
|
let main_pod = MainPodVerifyCircuit {
|
||||||
|
|
@ -328,12 +328,22 @@ impl PodProver for Prover {
|
||||||
let data = builder.build::<C>();
|
let data = builder.build::<C>();
|
||||||
let proof = data.prove(pw)?;
|
let proof = data.prove(pw)?;
|
||||||
|
|
||||||
Ok(Box::new(MainPod {
|
Ok(MainPod {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
id,
|
id,
|
||||||
public_statements,
|
public_statements,
|
||||||
proof,
|
proof,
|
||||||
}))
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PodProver for Prover {
|
||||||
|
fn prove(
|
||||||
|
&mut self,
|
||||||
|
params: &Params,
|
||||||
|
inputs: MainPodInputs,
|
||||||
|
) -> Result<Box<dyn Pod>, Box<DynError>> {
|
||||||
|
Ok(self._prove(params, inputs).map(Box::new)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,16 +374,12 @@ pub(crate) fn normalize_statement(statement: &Statement, self_id: PodId) -> midd
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MainPod {
|
impl MainPod {
|
||||||
fn verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
// 2. get the id out of the public statements
|
// 2. get the id out of the public statements
|
||||||
let id: PodId = PodId(hash_statements(&self.public_statements, &self.params));
|
let id: PodId = PodId(hash_statements(&self.public_statements, &self.params));
|
||||||
if id != self.id {
|
if id != self.id {
|
||||||
return Err(anyhow!(
|
return Err(Error::id_not_equal(self.id, id));
|
||||||
"id does not match, expected {}, computed {}",
|
|
||||||
self.id,
|
|
||||||
id
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1, 3, 4, 5 verification via the zkSNARK proof
|
// 1, 3, 4, 5 verification via the zkSNARK proof
|
||||||
|
|
@ -387,7 +393,13 @@ impl Pod for MainPod {
|
||||||
|
|
||||||
let data = builder.build::<C>();
|
let data = builder.build::<C>();
|
||||||
data.verify(self.proof.clone())
|
data.verify(self.proof.clone())
|
||||||
.map_err(|e| anyhow!("MainPod proof verification failure: {:?}", e))
|
.map_err(|e| Error::custom(format!("MainPod proof verification failure: {:?}", e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pod for MainPod {
|
||||||
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
|
Ok(self._verify()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
|
|
@ -418,13 +430,14 @@ pub mod tests {
|
||||||
signedpod::Signer,
|
signedpod::Signer,
|
||||||
},
|
},
|
||||||
examples::{zu_kyc_pod_builder, zu_kyc_sign_pod_builders},
|
examples::{zu_kyc_pod_builder, zu_kyc_sign_pod_builders},
|
||||||
frontend, middleware,
|
frontend::{self},
|
||||||
|
middleware,
|
||||||
middleware::RawValue,
|
middleware::RawValue,
|
||||||
op,
|
op,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_main_zu_kyc() -> Result<()> {
|
fn test_main_zu_kyc() -> frontend::Result<()> {
|
||||||
let params = middleware::Params {
|
let params = middleware::Params {
|
||||||
// Currently the circuit uses random access that only supports vectors of length 64.
|
// Currently the circuit uses random access that only supports vectors of length 64.
|
||||||
// With max_input_main_pods=3 we need random access to a vector of length 73.
|
// With max_input_main_pods=3 we need random access to a vector of length 73.
|
||||||
|
|
@ -447,7 +460,7 @@ pub mod tests {
|
||||||
let kyc_pod = kyc_builder.prove(&mut prover, ¶ms)?;
|
let kyc_pod = kyc_builder.prove(&mut prover, ¶ms)?;
|
||||||
let pod = (kyc_pod.pod as Box<dyn Any>).downcast::<MainPod>().unwrap();
|
let pod = (kyc_pod.pod as Box<dyn Any>).downcast::<MainPod>().unwrap();
|
||||||
|
|
||||||
pod.verify()
|
Ok(pod.verify()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{mainpod::Statement, primitives::merkletree::MerkleClaimAndProof},
|
backends::plonky2::{
|
||||||
|
error::{Error, Result},
|
||||||
|
mainpod::Statement,
|
||||||
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
|
},
|
||||||
middleware::{self, OperationType, Params, ToFields, F},
|
middleware::{self, OperationType, Params, ToFields, F},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -78,12 +81,16 @@ impl Operation {
|
||||||
OperationAux::MerkleProofIndex(i) => crate::middleware::OperationAux::MerkleProof(
|
OperationAux::MerkleProofIndex(i) => crate::middleware::OperationAux::MerkleProof(
|
||||||
merkle_proofs
|
merkle_proofs
|
||||||
.get(i)
|
.get(i)
|
||||||
.ok_or(anyhow!("Missing Merkle proof index {}", i))?
|
.ok_or(Error::custom(format!("Missing Merkle proof index {}", i)))?
|
||||||
.proof
|
.proof
|
||||||
.clone(),
|
.clone(),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
middleware::Operation::op(self.0.clone(), &deref_args, &deref_aux)
|
Ok(middleware::Operation::op(
|
||||||
|
self.0.clone(),
|
||||||
|
&deref_args,
|
||||||
|
&deref_aux,
|
||||||
|
)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::middleware::{
|
use crate::{
|
||||||
self, NativePredicate, Params, Predicate, StatementArg, ToFields, WildcardValue,
|
backends::plonky2::error::{Error, Result},
|
||||||
|
middleware::{self, NativePredicate, Params, Predicate, StatementArg, ToFields, WildcardValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
|
@ -36,7 +36,7 @@ impl ToFields for Statement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Statement> for middleware::Statement {
|
impl TryFrom<Statement> for middleware::Statement {
|
||||||
type Error = anyhow::Error;
|
type Error = Error;
|
||||||
fn try_from(s: Statement) -> Result<Self> {
|
fn try_from(s: Statement) -> Result<Self> {
|
||||||
type S = middleware::Statement;
|
type S = middleware::Statement;
|
||||||
type NP = NativePredicate;
|
type NP = NativePredicate;
|
||||||
|
|
@ -78,7 +78,10 @@ impl TryFrom<Statement> for middleware::Statement {
|
||||||
(NP::MaxOf, (Some(SA::Key(ak1)), Some(SA::Key(ak2)), Some(SA::Key(ak3))), 3) => {
|
(NP::MaxOf, (Some(SA::Key(ak1)), Some(SA::Key(ak2)), Some(SA::Key(ak3))), 3) => {
|
||||||
S::MaxOf(ak1, ak2, ak3)
|
S::MaxOf(ak1, ak2, ak3)
|
||||||
}
|
}
|
||||||
_ => Err(anyhow!("Ill-formed statement expression {:?}", s))?,
|
_ => Err(Error::custom(format!(
|
||||||
|
"Ill-formed statement expression {:?}",
|
||||||
|
s
|
||||||
|
)))?,
|
||||||
},
|
},
|
||||||
Predicate::Custom(cpr) => {
|
Predicate::Custom(cpr) => {
|
||||||
let vs: Vec<WildcardValue> = proper_args
|
let vs: Vec<WildcardValue> = proper_args
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
|
error::{Error, Result},
|
||||||
mainpod::{
|
mainpod::{
|
||||||
extract_merkle_proofs, hash_statements, layout_statements, normalize_statement,
|
extract_merkle_proofs, hash_statements, layout_statements, normalize_statement,
|
||||||
process_private_statements_operations, process_public_statements_operations, Operation,
|
process_private_statements_operations, process_public_statements_operations, Operation,
|
||||||
|
|
@ -18,15 +18,19 @@ use crate::{
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, hash_str, AnchoredKey, MainPodInputs, NativePredicate, Params, Pod, PodId, PodProver,
|
self, hash_str, AnchoredKey, DynError, MainPodInputs, NativePredicate, Params, Pod, PodId,
|
||||||
Predicate, StatementArg, KEY_TYPE, SELF,
|
PodProver, Predicate, StatementArg, KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct MockProver {}
|
pub struct MockProver {}
|
||||||
|
|
||||||
impl PodProver for MockProver {
|
impl PodProver for MockProver {
|
||||||
fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result<Box<dyn Pod>> {
|
fn prove(
|
||||||
|
&mut self,
|
||||||
|
params: &Params,
|
||||||
|
inputs: MainPodInputs,
|
||||||
|
) -> Result<Box<dyn Pod>, Box<DynError>> {
|
||||||
Ok(Box::new(MockMainPod::new(params, inputs)?))
|
Ok(Box::new(MockMainPod::new(params, inputs)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,10 +181,8 @@ impl MockMainPod {
|
||||||
|
|
||||||
Ok(pod)
|
Ok(pod)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Pod for MockMainPod {
|
fn _verify(&self) -> Result<()> {
|
||||||
fn verify(&self) -> Result<()> {
|
|
||||||
// 1. TODO: Verify input pods
|
// 1. TODO: Verify input pods
|
||||||
|
|
||||||
let input_statement_offset = self.offset_input_statements();
|
let input_statement_offset = self.offset_input_statements();
|
||||||
|
|
@ -245,24 +247,28 @@ impl Pod for MockMainPod {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.check_and_log(&self.params, &s.clone().try_into().unwrap())
|
.check_and_log(&self.params, &s.clone().try_into().unwrap())
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()
|
.collect::<Result<Vec<_>, middleware::Error>>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if !ids_match {
|
if !ids_match {
|
||||||
return Err(anyhow!("Verification failed: POD ID is incorrect."));
|
return Err(Error::pod_id_invalid());
|
||||||
}
|
}
|
||||||
if !has_type_statement {
|
if !has_type_statement {
|
||||||
return Err(anyhow!(
|
return Err(Error::not_type_statement());
|
||||||
"Verification failed: POD does not have type statement."
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if !value_ofs_unique {
|
if !value_ofs_unique {
|
||||||
return Err(anyhow!("Verification failed: Repeated ValueOf"));
|
return Err(Error::repeated_value_of());
|
||||||
}
|
}
|
||||||
if !statement_check.iter().all(|b| *b) {
|
if !statement_check.iter().all(|b| *b) {
|
||||||
return Err(anyhow!("Verification failed: Statement did not check."));
|
return Err(Error::statement_not_check());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pod for MockMainPod {
|
||||||
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
|
Ok(self._verify()?)
|
||||||
|
}
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
@ -293,11 +299,12 @@ pub mod tests {
|
||||||
great_boy_pod_full_flow, tickets_pod_full_flow, zu_kyc_pod_builder,
|
great_boy_pod_full_flow, tickets_pod_full_flow, zu_kyc_pod_builder,
|
||||||
zu_kyc_sign_pod_builders,
|
zu_kyc_sign_pod_builders,
|
||||||
},
|
},
|
||||||
|
frontend,
|
||||||
middleware::{self},
|
middleware::{self},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mock_main_zu_kyc() -> Result<()> {
|
fn test_mock_main_zu_kyc() -> frontend::Result<()> {
|
||||||
let params = middleware::Params::default();
|
let params = middleware::Params::default();
|
||||||
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
|
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
|
||||||
zu_kyc_sign_pod_builders(¶ms);
|
zu_kyc_sign_pod_builders(¶ms);
|
||||||
|
|
@ -331,7 +338,7 @@ pub mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mock_main_great_boy() -> Result<()> {
|
fn test_mock_main_great_boy() -> frontend::Result<()> {
|
||||||
let params = middleware::Params::default();
|
let params = middleware::Params::default();
|
||||||
let great_boy_builder = great_boy_pod_full_flow()?;
|
let great_boy_builder = great_boy_pod_full_flow()?;
|
||||||
|
|
||||||
|
|
@ -349,7 +356,7 @@ pub mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mock_main_tickets() -> Result<()> {
|
fn test_mock_main_tickets() -> frontend::Result<()> {
|
||||||
let params = middleware::Params::default();
|
let params = middleware::Params::default();
|
||||||
let tickets_builder = tickets_pod_full_flow()?;
|
let tickets_builder = tickets_pod_full_flow()?;
|
||||||
let mut prover = MockProver {};
|
let mut prover = MockProver {};
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::primitives::merkletree::MerkleTree,
|
backends::plonky2::{
|
||||||
|
error::{Error, Result},
|
||||||
|
primitives::merkletree::MerkleTree,
|
||||||
|
},
|
||||||
constants::MAX_DEPTH,
|
constants::MAX_DEPTH,
|
||||||
middleware::{
|
middleware::{
|
||||||
containers::Dictionary, hash_str, AnchoredKey, Hash, Key, Params, Pod, PodId, PodSigner,
|
containers::Dictionary, hash_str, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId,
|
||||||
PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
PodSigner, PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -22,8 +24,8 @@ impl MockSigner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PodSigner for MockSigner {
|
impl MockSigner {
|
||||||
fn sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<Box<dyn Pod>> {
|
fn _sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<MockSignedPod> {
|
||||||
let mut kvs = kvs.clone();
|
let mut kvs = kvs.clone();
|
||||||
let pubkey = self.pubkey();
|
let pubkey = self.pubkey();
|
||||||
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey));
|
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey));
|
||||||
|
|
@ -32,7 +34,17 @@ impl PodSigner for MockSigner {
|
||||||
let dict = Dictionary::new(kvs.clone())?;
|
let dict = Dictionary::new(kvs.clone())?;
|
||||||
let id = PodId(dict.commitment());
|
let id = PodId(dict.commitment());
|
||||||
let signature = format!("{}_signed_by_{}", id, pubkey);
|
let signature = format!("{}_signed_by_{}", id, pubkey);
|
||||||
Ok(Box::new(MockSignedPod { id, signature, kvs }))
|
Ok(MockSignedPod { id, signature, kvs })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PodSigner for MockSigner {
|
||||||
|
fn sign(
|
||||||
|
&mut self,
|
||||||
|
params: &Params,
|
||||||
|
kvs: &HashMap<Key, Value>,
|
||||||
|
) -> Result<Box<dyn Pod>, Box<DynError>> {
|
||||||
|
Ok(self._sign(params, kvs).map(Box::new)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,8 +61,8 @@ impl MockSignedPod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MockSignedPod {
|
impl MockSignedPod {
|
||||||
fn verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
// 1. Verify id
|
// 1. Verify id
|
||||||
let mt = MerkleTree::new(
|
let mt = MerkleTree::new(
|
||||||
MAX_DEPTH,
|
MAX_DEPTH,
|
||||||
|
|
@ -62,23 +74,18 @@ impl Pod for MockSignedPod {
|
||||||
)?;
|
)?;
|
||||||
let id = PodId(mt.root());
|
let id = PodId(mt.root());
|
||||||
if id != self.id {
|
if id != self.id {
|
||||||
return Err(anyhow!(
|
return Err(Error::id_not_equal(self.id, id));
|
||||||
"id does not match, expected {}, computed {}",
|
|
||||||
self.id,
|
|
||||||
id
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Verify type
|
// 2. Verify type
|
||||||
let value_at_type = self
|
let value_at_type = self
|
||||||
.kvs
|
.kvs
|
||||||
.get(&Key::from(KEY_TYPE))
|
.get(&Key::from(KEY_TYPE))
|
||||||
.ok_or(anyhow!("key not found"))?;
|
.ok_or(Error::key_not_found())?;
|
||||||
if &Value::from(PodType::MockSigned) != value_at_type {
|
if &Value::from(PodType::MockSigned) != value_at_type {
|
||||||
return Err(anyhow!(
|
return Err(Error::type_not_equal(
|
||||||
"type does not match, expected MockSigned ({}), found {}",
|
|
||||||
PodType::MockSigned,
|
PodType::MockSigned,
|
||||||
value_at_type
|
value_at_type.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,18 +93,23 @@ impl Pod for MockSignedPod {
|
||||||
let pk_hash = self
|
let pk_hash = self
|
||||||
.kvs
|
.kvs
|
||||||
.get(&Key::from(KEY_SIGNER))
|
.get(&Key::from(KEY_SIGNER))
|
||||||
.ok_or(anyhow!("key not found"))?;
|
.ok_or(Error::key_not_found())?;
|
||||||
let signature = format!("{}_signed_by_{}", id, pk_hash);
|
let signature = format!("{}_signed_by_{}", id, pk_hash);
|
||||||
if signature != self.signature {
|
if signature != self.signature {
|
||||||
return Err(anyhow!(
|
return Err(Error::custom(format!(
|
||||||
"signature does not match, expected {}, computed {}",
|
"signature does not match, expected {}, computed {}",
|
||||||
self.id,
|
self.id, id
|
||||||
id
|
)));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pod for MockSignedPod {
|
||||||
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
|
Ok(self._verify()?)
|
||||||
|
}
|
||||||
|
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
|
|
@ -149,7 +161,7 @@ pub mod tests {
|
||||||
.downcast::<MockSignedPod>()
|
.downcast::<MockSignedPod>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
pod.verify()?;
|
pod._verify()?;
|
||||||
println!("id: {}", pod.id());
|
println!("id: {}", pod.id());
|
||||||
println!("kvs: {:?}", pod.kvs());
|
println!("kvs: {:?}", pod.kvs());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
pub mod basetypes;
|
pub mod basetypes;
|
||||||
pub mod circuits;
|
pub mod circuits;
|
||||||
|
mod error;
|
||||||
pub mod mainpod;
|
pub mod mainpod;
|
||||||
pub mod mock;
|
pub mod mock;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod signedpod;
|
pub mod signedpod;
|
||||||
|
|
||||||
|
pub use error::*;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
//!
|
//!
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
field::types::Field,
|
field::types::Field,
|
||||||
hash::{
|
hash::{
|
||||||
|
|
@ -28,6 +27,7 @@ use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::D,
|
basetypes::D,
|
||||||
circuits::common::{CircuitBuilderPod, ValueTarget},
|
circuits::common::{CircuitBuilderPod, ValueTarget},
|
||||||
|
error::Result,
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
},
|
},
|
||||||
middleware::{EMPTY_HASH, EMPTY_VALUE, F, HASH_SIZE},
|
middleware::{EMPTY_HASH, EMPTY_VALUE, F, HASH_SIZE},
|
||||||
|
|
@ -408,7 +408,10 @@ pub mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{basetypes::C, primitives::merkletree::*},
|
backends::plonky2::{
|
||||||
|
basetypes::C,
|
||||||
|
primitives::merkletree::{keypath, kv_hash, MerkleTree},
|
||||||
|
},
|
||||||
middleware::{hash_value, RawValue},
|
middleware::{hash_value, RawValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -693,6 +696,8 @@ pub mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MerkleTree::verify(max_depth, tree2.root(), &proof, &key, &value)
|
MerkleTree::verify(max_depth, tree2.root(), &proof, &key, &value)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
|
.inner()
|
||||||
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
"proof of inclusion does not verify"
|
"proof of inclusion does not verify"
|
||||||
);
|
);
|
||||||
79
src/backends/plonky2/primitives/merkletree/error.rs
Normal file
79
src/backends/plonky2/primitives/merkletree/error.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
//! tree errors
|
||||||
|
|
||||||
|
use std::{backtrace::Backtrace, fmt::Debug};
|
||||||
|
|
||||||
|
pub type TreeResult<T, E = TreeError> = core::result::Result<T, E>;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum TreeInnerError {
|
||||||
|
#[error("key not found")]
|
||||||
|
KeyNotFound,
|
||||||
|
#[error("key already exists")]
|
||||||
|
KeyExists,
|
||||||
|
#[error("max depth reached")]
|
||||||
|
MaxDepth,
|
||||||
|
#[error("reached empty node, should not have entered")]
|
||||||
|
EmptyNode,
|
||||||
|
#[error("proof of {0} does not verify")]
|
||||||
|
ProofFail(String), // inclusion / exclusion
|
||||||
|
#[error("invalid {0} proof")]
|
||||||
|
InvalidProof(String),
|
||||||
|
#[error("key too short (key length: {0}) for the max_depth: {1}")]
|
||||||
|
TooShortKey(usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error)]
|
||||||
|
pub enum TreeError {
|
||||||
|
#[error("Inner: {inner}\n{backtrace}")]
|
||||||
|
Inner {
|
||||||
|
inner: Box<TreeInnerError>,
|
||||||
|
backtrace: Box<Backtrace>,
|
||||||
|
},
|
||||||
|
#[error("anyhow::Error: {0}")]
|
||||||
|
Anyhow(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for TreeError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! new {
|
||||||
|
($inner:expr) => {
|
||||||
|
TreeError::Inner {
|
||||||
|
inner: Box::new($inner),
|
||||||
|
backtrace: Box::new(Backtrace::capture()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
use TreeInnerError::*;
|
||||||
|
impl TreeError {
|
||||||
|
pub fn inner(&self) -> Option<&TreeInnerError> {
|
||||||
|
match self {
|
||||||
|
Self::Inner { inner, .. } => Some(inner),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) fn key_not_found() -> Self {
|
||||||
|
new!(KeyNotFound)
|
||||||
|
}
|
||||||
|
pub(crate) fn key_exists() -> Self {
|
||||||
|
new!(KeyExists)
|
||||||
|
}
|
||||||
|
pub(crate) fn max_depth() -> Self {
|
||||||
|
new!(MaxDepth)
|
||||||
|
}
|
||||||
|
pub(crate) fn empty_node() -> Self {
|
||||||
|
new!(EmptyNode)
|
||||||
|
}
|
||||||
|
pub(crate) fn proof_fail(obj: String) -> Self {
|
||||||
|
new!(ProofFail(obj))
|
||||||
|
}
|
||||||
|
pub(crate) fn invalid_proof(obj: String) -> Self {
|
||||||
|
new!(InvalidProof(obj))
|
||||||
|
}
|
||||||
|
pub(crate) fn too_short_key(depth: usize, max_depth: usize) -> Self {
|
||||||
|
new!(TooShortKey(depth, max_depth))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,13 +2,16 @@
|
||||||
//! https://0xparc.github.io/pod2/merkletree.html .
|
//! https://0xparc.github.io/pod2/merkletree.html .
|
||||||
use std::{collections::HashMap, fmt, iter::IntoIterator};
|
use std::{collections::HashMap, fmt, iter::IntoIterator};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub use super::merkletree_circuit::*;
|
|
||||||
use crate::middleware::{hash_fields, Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F};
|
use crate::middleware::{hash_fields, Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F};
|
||||||
|
|
||||||
|
pub mod circuit;
|
||||||
|
pub use circuit::*;
|
||||||
|
pub mod error;
|
||||||
|
pub use error::{TreeError, TreeResult};
|
||||||
|
|
||||||
/// Implements the MerkleTree specified at
|
/// Implements the MerkleTree specified at
|
||||||
/// https://0xparc.github.io/pod2/merkletree.html
|
/// https://0xparc.github.io/pod2/merkletree.html
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -19,12 +22,12 @@ pub struct MerkleTree {
|
||||||
|
|
||||||
impl MerkleTree {
|
impl MerkleTree {
|
||||||
/// builds a new `MerkleTree` where the leaves contain the given key-values
|
/// builds a new `MerkleTree` where the leaves contain the given key-values
|
||||||
pub fn new(max_depth: usize, kvs: &HashMap<RawValue, RawValue>) -> Result<Self> {
|
pub fn new(max_depth: usize, kvs: &HashMap<RawValue, RawValue>) -> TreeResult<Self> {
|
||||||
// Construct leaves.
|
// Construct leaves.
|
||||||
let mut leaves: Vec<_> = kvs
|
let mut leaves: Vec<_> = kvs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| Leaf::new(max_depth, *k, *v))
|
.map(|(k, v)| Leaf::new(max_depth, *k, *v))
|
||||||
.collect::<Result<_>>()?;
|
.collect::<TreeResult<_>>()?;
|
||||||
|
|
||||||
// Start with a leaf or conclude with an empty node as root.
|
// Start with a leaf or conclude with an empty node as root.
|
||||||
let mut root = leaves.pop().map(Node::Leaf).unwrap_or(Node::None);
|
let mut root = leaves.pop().map(Node::Leaf).unwrap_or(Node::None);
|
||||||
|
|
@ -50,17 +53,17 @@ impl MerkleTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns the value at the given key
|
/// returns the value at the given key
|
||||||
pub fn get(&self, key: &RawValue) -> Result<RawValue> {
|
pub fn get(&self, key: &RawValue) -> TreeResult<RawValue> {
|
||||||
let path = keypath(self.max_depth, *key)?;
|
let path = keypath(self.max_depth, *key)?;
|
||||||
let key_resolution = self.root.down(0, self.max_depth, path, None)?;
|
let key_resolution = self.root.down(0, self.max_depth, path, None)?;
|
||||||
match key_resolution {
|
match key_resolution {
|
||||||
Some((k, v)) if &k == key => Ok(v),
|
Some((k, v)) if &k == key => Ok(v),
|
||||||
_ => Err(anyhow!("key not found")),
|
_ => Err(TreeError::key_not_found()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns a boolean indicating whether the key exists in the tree
|
/// returns a boolean indicating whether the key exists in the tree
|
||||||
pub fn contains(&self, key: &RawValue) -> Result<bool> {
|
pub fn contains(&self, key: &RawValue) -> TreeResult<bool> {
|
||||||
let path = keypath(self.max_depth, *key)?;
|
let path = keypath(self.max_depth, *key)?;
|
||||||
match self.root.down(0, self.max_depth, path, None) {
|
match self.root.down(0, self.max_depth, path, None) {
|
||||||
Ok(Some((k, _))) => {
|
Ok(Some((k, _))) => {
|
||||||
|
|
@ -77,7 +80,7 @@ impl MerkleTree {
|
||||||
/// returns a proof of existence, which proves that the given key exists in
|
/// returns a proof of existence, which proves that the given key exists in
|
||||||
/// the tree. It returns the `value` of the leaf at the given `key`, and the
|
/// the tree. It returns the `value` of the leaf at the given `key`, and the
|
||||||
/// `MerkleProof`.
|
/// `MerkleProof`.
|
||||||
pub fn prove(&self, key: &RawValue) -> Result<(RawValue, MerkleProof)> {
|
pub fn prove(&self, key: &RawValue) -> TreeResult<(RawValue, MerkleProof)> {
|
||||||
let path = keypath(self.max_depth, *key)?;
|
let path = keypath(self.max_depth, *key)?;
|
||||||
|
|
||||||
let mut siblings: Vec<Hash> = Vec::new();
|
let mut siblings: Vec<Hash> = Vec::new();
|
||||||
|
|
@ -94,7 +97,7 @@ impl MerkleTree {
|
||||||
other_leaf: None,
|
other_leaf: None,
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
_ => Err(anyhow!("key not found")),
|
_ => Err(TreeError::key_not_found()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,7 +105,7 @@ impl MerkleTree {
|
||||||
/// `key` does not exist in the tree. The return value specifies
|
/// `key` does not exist in the tree. The return value specifies
|
||||||
/// the key-value pair in the leaf reached as a result of
|
/// the key-value pair in the leaf reached as a result of
|
||||||
/// resolving `key` as well as a `MerkleProof`.
|
/// resolving `key` as well as a `MerkleProof`.
|
||||||
pub fn prove_nonexistence(&self, key: &RawValue) -> Result<MerkleProof> {
|
pub fn prove_nonexistence(&self, key: &RawValue) -> TreeResult<MerkleProof> {
|
||||||
let path = keypath(self.max_depth, *key)?;
|
let path = keypath(self.max_depth, *key)?;
|
||||||
|
|
||||||
let mut siblings: Vec<Hash> = Vec::new();
|
let mut siblings: Vec<Hash> = Vec::new();
|
||||||
|
|
@ -124,7 +127,7 @@ impl MerkleTree {
|
||||||
siblings,
|
siblings,
|
||||||
other_leaf: Some((k, v)),
|
other_leaf: Some((k, v)),
|
||||||
}),
|
}),
|
||||||
_ => Err(anyhow!("key found")),
|
_ => Err(TreeError::key_not_found()),
|
||||||
}
|
}
|
||||||
// both cases prove that the given key don't exist in the tree. ∎
|
// both cases prove that the given key don't exist in the tree. ∎
|
||||||
}
|
}
|
||||||
|
|
@ -136,11 +139,11 @@ impl MerkleTree {
|
||||||
proof: &MerkleProof,
|
proof: &MerkleProof,
|
||||||
key: &RawValue,
|
key: &RawValue,
|
||||||
value: &RawValue,
|
value: &RawValue,
|
||||||
) -> Result<()> {
|
) -> TreeResult<()> {
|
||||||
let h = proof.compute_root_from_leaf(max_depth, key, Some(*value))?;
|
let h = proof.compute_root_from_leaf(max_depth, key, Some(*value))?;
|
||||||
|
|
||||||
if h != root {
|
if h != root {
|
||||||
Err(anyhow!("proof of inclusion does not verify"))
|
Err(TreeError::proof_fail("inclusion".to_string()))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -153,16 +156,18 @@ impl MerkleTree {
|
||||||
root: Hash,
|
root: Hash,
|
||||||
proof: &MerkleProof,
|
proof: &MerkleProof,
|
||||||
key: &RawValue,
|
key: &RawValue,
|
||||||
) -> Result<()> {
|
) -> TreeResult<()> {
|
||||||
match proof.other_leaf {
|
match proof.other_leaf {
|
||||||
Some((k, _v)) if &k == key => Err(anyhow!("Invalid non-existence proof.")),
|
Some((k, _v)) if &k == key => {
|
||||||
|
Err(TreeError::invalid_proof("non-existence".to_string()))
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let k = proof.other_leaf.map(|(k, _)| k).unwrap_or(*key);
|
let k = proof.other_leaf.map(|(k, _)| k).unwrap_or(*key);
|
||||||
let v: Option<RawValue> = proof.other_leaf.map(|(_, v)| v);
|
let v: Option<RawValue> = proof.other_leaf.map(|(_, v)| v);
|
||||||
let h = proof.compute_root_from_leaf(max_depth, &k, v)?;
|
let h = proof.compute_root_from_leaf(max_depth, &k, v)?;
|
||||||
|
|
||||||
if h != root {
|
if h != root {
|
||||||
Err(anyhow!("proof of exclusion does not verify"))
|
Err(TreeError::proof_fail("exclusion".to_string()))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -240,9 +245,9 @@ impl MerkleProof {
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
key: &RawValue,
|
key: &RawValue,
|
||||||
value: Option<RawValue>,
|
value: Option<RawValue>,
|
||||||
) -> Result<Hash> {
|
) -> TreeResult<Hash> {
|
||||||
if self.siblings.len() >= max_depth {
|
if self.siblings.len() >= max_depth {
|
||||||
return Err(anyhow!("max depth reached"));
|
return Err(TreeError::max_depth());
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = keypath(max_depth, *key)?;
|
let path = keypath(max_depth, *key)?;
|
||||||
|
|
@ -372,9 +377,9 @@ impl Node {
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
path: Vec<bool>,
|
path: Vec<bool>,
|
||||||
mut siblings: Option<&mut Vec<Hash>>,
|
mut siblings: Option<&mut Vec<Hash>>,
|
||||||
) -> Result<Option<(RawValue, RawValue)>> {
|
) -> TreeResult<Option<(RawValue, RawValue)>> {
|
||||||
if lvl >= max_depth {
|
if lvl >= max_depth {
|
||||||
return Err(anyhow!("max depth reached"));
|
return Err(TreeError::max_depth());
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -402,9 +407,9 @@ impl Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds the leaf at the tree from the current node (self), without computing any hash
|
// adds the leaf at the tree from the current node (self), without computing any hash
|
||||||
pub(crate) fn add_leaf(&mut self, lvl: usize, max_depth: usize, leaf: Leaf) -> Result<()> {
|
pub(crate) fn add_leaf(&mut self, lvl: usize, max_depth: usize, leaf: Leaf) -> TreeResult<()> {
|
||||||
if lvl >= max_depth {
|
if lvl >= max_depth {
|
||||||
return Err(anyhow!("max depth reached"));
|
return Err(TreeError::max_depth());
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -436,7 +441,7 @@ impl Node {
|
||||||
// Note: current approach returns an error when trying to
|
// Note: current approach returns an error when trying to
|
||||||
// add to a leaf where the key already exists. We could also
|
// add to a leaf where the key already exists. We could also
|
||||||
// ignore it if needed.
|
// ignore it if needed.
|
||||||
return Err(anyhow!("key already exists"));
|
return Err(TreeError::key_exists());
|
||||||
}
|
}
|
||||||
let old_leaf = l.clone();
|
let old_leaf = l.clone();
|
||||||
// set self as an intermediate node
|
// set self as an intermediate node
|
||||||
|
|
@ -444,7 +449,7 @@ impl Node {
|
||||||
return self.down_till_divergence(lvl, max_depth, old_leaf, leaf);
|
return self.down_till_divergence(lvl, max_depth, old_leaf, leaf);
|
||||||
}
|
}
|
||||||
Self::None => {
|
Self::None => {
|
||||||
return Err(anyhow!("reached empty node, should not have entered"));
|
return Err(TreeError::empty_node());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -460,9 +465,9 @@ impl Node {
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
old_leaf: Leaf,
|
old_leaf: Leaf,
|
||||||
new_leaf: Leaf,
|
new_leaf: Leaf,
|
||||||
) -> Result<()> {
|
) -> TreeResult<()> {
|
||||||
if lvl >= max_depth {
|
if lvl >= max_depth {
|
||||||
return Err(anyhow!("max depth reached"));
|
return Err(TreeError::max_depth());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Node::Intermediate(ref mut n) = self {
|
if let Node::Intermediate(ref mut n) = self {
|
||||||
|
|
@ -535,7 +540,7 @@ struct Leaf {
|
||||||
value: RawValue,
|
value: RawValue,
|
||||||
}
|
}
|
||||||
impl Leaf {
|
impl Leaf {
|
||||||
fn new(max_depth: usize, key: RawValue, value: RawValue) -> Result<Self> {
|
fn new(max_depth: usize, key: RawValue, value: RawValue) -> TreeResult<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
hash: None,
|
hash: None,
|
||||||
path: keypath(max_depth, key)?,
|
path: keypath(max_depth, key)?,
|
||||||
|
|
@ -560,17 +565,13 @@ impl Leaf {
|
||||||
// max-depth? ie, what happens when two keys share the same path for more bits
|
// max-depth? ie, what happens when two keys share the same path for more bits
|
||||||
// than the max_depth?
|
// than the max_depth?
|
||||||
/// returns the path of the given key
|
/// returns the path of the given key
|
||||||
pub(crate) fn keypath(max_depth: usize, k: RawValue) -> Result<Vec<bool>> {
|
pub(crate) fn keypath(max_depth: usize, k: RawValue) -> TreeResult<Vec<bool>> {
|
||||||
let bytes = k.to_bytes();
|
let bytes = k.to_bytes();
|
||||||
if max_depth > 8 * bytes.len() {
|
if max_depth > 8 * bytes.len() {
|
||||||
// note that our current keys are of Value type, which are 4 Goldilocks
|
// note that our current keys are of Value type, which are 4 Goldilocks
|
||||||
// field elements, ie ~256 bits, therefore the max_depth can not be
|
// field elements, ie ~256 bits, therefore the max_depth can not be
|
||||||
// bigger than 256.
|
// bigger than 256.
|
||||||
return Err(anyhow!(
|
return Err(TreeError::too_short_key(8 * bytes.len(), max_depth));
|
||||||
"key to short (key length: {}) for the max_depth: {}",
|
|
||||||
8 * bytes.len(),
|
|
||||||
max_depth
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Ok((0..max_depth)
|
Ok((0..max_depth)
|
||||||
.map(|n| bytes[n / 8] & (1 << (n % 8)) != 0)
|
.map(|n| bytes[n / 8] & (1 << (n % 8)) != 0)
|
||||||
|
|
@ -617,7 +618,7 @@ pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_merkletree() -> Result<()> {
|
fn test_merkletree() -> TreeResult<()> {
|
||||||
let mut kvs = HashMap::new();
|
let mut kvs = HashMap::new();
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
|
|
@ -1,4 +1,2 @@
|
||||||
pub mod merkletree;
|
pub mod merkletree;
|
||||||
mod merkletree_circuit;
|
|
||||||
pub mod signature;
|
pub mod signature;
|
||||||
mod signature_circuit;
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use anyhow::Result;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
field::types::Field,
|
field::types::Field,
|
||||||
|
|
@ -26,8 +25,9 @@ use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::{Proof, C, D},
|
basetypes::{Proof, C, D},
|
||||||
circuits::common::{CircuitBuilderPod, ValueTarget},
|
circuits::common::{CircuitBuilderPod, ValueTarget},
|
||||||
|
error::Result,
|
||||||
primitives::signature::{
|
primitives::signature::{
|
||||||
PublicKey, SecretKey, Signature, DUMMY_PUBLIC_INPUTS, DUMMY_SIGNATURE,
|
PublicKey, SecretKey, Signature, DUMMY_PUBLIC_INPUTS, DUMMY_SIGNATURE, VP,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
middleware::{Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F, VALUE_SIZE},
|
middleware::{Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F, VALUE_SIZE},
|
||||||
|
|
@ -67,7 +67,7 @@ impl SignatureVerifyGadget {
|
||||||
pub fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<SignatureVerifyTarget> {
|
pub fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<SignatureVerifyTarget> {
|
||||||
let enabled = builder.add_virtual_bool_target_safe();
|
let enabled = builder.add_virtual_bool_target_safe();
|
||||||
|
|
||||||
let common_data = super::signature::VP.0.common.clone();
|
let common_data = VP.0.common.clone();
|
||||||
|
|
||||||
// targets related to the 'public inputs' for the verification of the
|
// targets related to the 'public inputs' for the verification of the
|
||||||
// `SignatureInternalCircuit` proof.
|
// `SignatureInternalCircuit` proof.
|
||||||
|
|
@ -161,10 +161,7 @@ impl SignatureVerifyTarget {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pw.set_verifier_data_target(
|
pw.set_verifier_data_target(&self.verifier_data_targ, &VP.0.verifier_only)?;
|
||||||
&self.verifier_data_targ,
|
|
||||||
&super::signature::VP.0.verifier_only,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
//! Proof-based signatures using Plonky2 proofs, following
|
//! Proof-based signatures using Plonky2 proofs, following
|
||||||
//! https://eprint.iacr.org/2024/1553 .
|
//! https://eprint.iacr.org/2024/1553 .
|
||||||
use anyhow::Result;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
field::types::Sample,
|
field::types::Sample,
|
||||||
|
|
@ -20,9 +19,14 @@ use plonky2::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use super::signature_circuit::*;
|
pub mod circuit;
|
||||||
|
pub use circuit::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::basetypes::{Proof, C, D},
|
backends::plonky2::{
|
||||||
|
basetypes::{Proof, C, D},
|
||||||
|
error::{Error, Result},
|
||||||
|
},
|
||||||
middleware::{RawValue, F, VALUE_SIZE},
|
middleware::{RawValue, F, VALUE_SIZE},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -121,6 +125,7 @@ impl Signature {
|
||||||
proof: self.0.clone(),
|
proof: self.0.clone(),
|
||||||
public_inputs,
|
public_inputs,
|
||||||
})
|
})
|
||||||
|
.map_err(Error::plonky2_proof_fail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,24 +1,26 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::primitives::{
|
backends::plonky2::{
|
||||||
|
error::{Error, Result},
|
||||||
|
primitives::{
|
||||||
merkletree::MerkleTree,
|
merkletree::MerkleTree,
|
||||||
signature::{PublicKey, SecretKey, Signature},
|
signature::{PublicKey, SecretKey, Signature},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
constants::MAX_DEPTH,
|
constants::MAX_DEPTH,
|
||||||
middleware::{
|
middleware::{
|
||||||
containers::Dictionary, AnchoredKey, Hash, Key, Params, Pod, PodId, PodSigner, PodType,
|
containers::Dictionary, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId, PodSigner,
|
||||||
RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Signer(pub SecretKey);
|
pub struct Signer(pub SecretKey);
|
||||||
|
|
||||||
impl PodSigner for Signer {
|
impl Signer {
|
||||||
fn sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<Box<dyn Pod>> {
|
fn _sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<SignedPod> {
|
||||||
let mut kvs = kvs.clone();
|
let mut kvs = kvs.clone();
|
||||||
let pubkey = self.0.public_key();
|
let pubkey = self.0.public_key();
|
||||||
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey.0));
|
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey.0));
|
||||||
|
|
@ -28,11 +30,21 @@ impl PodSigner for Signer {
|
||||||
let id = RawValue::from(dict.commitment()); // PodId as Value
|
let id = RawValue::from(dict.commitment()); // PodId as Value
|
||||||
|
|
||||||
let signature: Signature = self.0.sign(id)?;
|
let signature: Signature = self.0.sign(id)?;
|
||||||
Ok(Box::new(SignedPod {
|
Ok(SignedPod {
|
||||||
id: PodId(Hash::from(id)),
|
id: PodId(Hash::from(id)),
|
||||||
signature,
|
signature,
|
||||||
dict,
|
dict,
|
||||||
}))
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PodSigner for Signer {
|
||||||
|
fn sign(
|
||||||
|
&mut self,
|
||||||
|
params: &Params,
|
||||||
|
kvs: &HashMap<Key, Value>,
|
||||||
|
) -> Result<Box<dyn Pod>, Box<DynError>> {
|
||||||
|
Ok(self._sign(params, kvs).map(Box::new)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,15 +55,14 @@ pub struct SignedPod {
|
||||||
pub dict: Dictionary,
|
pub dict: Dictionary,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for SignedPod {
|
impl SignedPod {
|
||||||
fn verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
// 1. Verify type
|
// 1. Verify type
|
||||||
let value_at_type = self.dict.get(&Key::from(KEY_TYPE))?;
|
let value_at_type = self.dict.get(&Key::from(KEY_TYPE))?;
|
||||||
if Value::from(PodType::Signed) != *value_at_type {
|
if Value::from(PodType::Signed) != *value_at_type {
|
||||||
return Err(anyhow!(
|
return Err(Error::type_not_equal(
|
||||||
"type does not match, expected Signed ({}), found {}",
|
|
||||||
PodType::Signed,
|
PodType::Signed,
|
||||||
value_at_type
|
value_at_type.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,11 +78,7 @@ impl Pod for SignedPod {
|
||||||
)?;
|
)?;
|
||||||
let id = PodId(mt.root());
|
let id = PodId(mt.root());
|
||||||
if id != self.id {
|
if id != self.id {
|
||||||
return Err(anyhow!(
|
return Err(Error::id_not_equal(self.id, id));
|
||||||
"id does not match, expected {}, computed {}",
|
|
||||||
self.id,
|
|
||||||
id
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Verify signature
|
// 3. Verify signature
|
||||||
|
|
@ -81,6 +88,12 @@ impl Pod for SignedPod {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pod for SignedPod {
|
||||||
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
|
Ok(self._verify().map_err(Box::new)?)
|
||||||
|
}
|
||||||
|
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
|
|
@ -135,7 +148,7 @@ pub mod tests {
|
||||||
let pod = pod.sign(&mut signer).unwrap();
|
let pod = pod.sign(&mut signer).unwrap();
|
||||||
let pod = (pod.pod as Box<dyn Any>).downcast::<SignedPod>().unwrap();
|
let pod = (pod.pod as Box<dyn Any>).downcast::<SignedPod>().unwrap();
|
||||||
|
|
||||||
pod.verify()?;
|
pod._verify()?;
|
||||||
println!("id: {}", pod.id());
|
println!("id: {}", pod.id());
|
||||||
println!("kvs: {:?}", pod.kvs());
|
println!("kvs: {:?}", pod.kvs());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use StatementTmplBuilder as STB;
|
use StatementTmplBuilder as STB;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frontend::{key, literal, CustomPredicateBatchBuilder, StatementTmplBuilder},
|
frontend::{key, literal, CustomPredicateBatchBuilder, Result, StatementTmplBuilder},
|
||||||
middleware::{
|
middleware::{
|
||||||
CustomPredicateBatch, CustomPredicateRef, NativePredicate as NP, Params, PodType,
|
CustomPredicateBatch, CustomPredicateRef, NativePredicate as NP, Params, PodType,
|
||||||
Predicate, KEY_SIGNER, KEY_TYPE,
|
Predicate, KEY_SIGNER, KEY_TYPE,
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@ pub mod custom;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use custom::{eth_dos_batch, eth_friend_batch};
|
use custom::{eth_dos_batch, eth_friend_batch};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::mock::signedpod::MockSigner,
|
backends::plonky2::mock::signedpod::MockSigner,
|
||||||
frontend::{MainPodBuilder, SignedPod, SignedPodBuilder},
|
frontend::{MainPodBuilder, Result, SignedPod, SignedPodBuilder},
|
||||||
middleware::{
|
middleware::{
|
||||||
containers::Set, CustomPredicateRef, Params, PodType, Statement, TypedValue, Value,
|
containers::Set, CustomPredicateRef, Params, PodType, Statement, TypedValue, Value,
|
||||||
KEY_SIGNER, KEY_TYPE,
|
KEY_SIGNER, KEY_TYPE,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use std::{collections::HashMap, fmt, hash as h, iter, iter::zip, sync::Arc};
|
use std::{collections::HashMap, fmt, hash as h, iter, iter::zip, sync::Arc};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frontend::{AnchoredKey, Statement, StatementArg},
|
frontend::{AnchoredKey, Error, Result, Statement, StatementArg},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, hash_str, CustomPredicate, CustomPredicateBatch, Key, KeyOrWildcard, NativePredicate,
|
self, hash_str, CustomPredicate, CustomPredicateBatch, Key, KeyOrWildcard, NativePredicate,
|
||||||
Params, PodId, Predicate, StatementTmpl, StatementTmplArg, ToFields, Value, Wildcard,
|
Params, PodId, Predicate, StatementTmpl, StatementTmplArg, ToFields, Value, Wildcard,
|
||||||
|
|
@ -131,17 +130,17 @@ impl CustomPredicateBatchBuilder {
|
||||||
sts: &[StatementTmplBuilder],
|
sts: &[StatementTmplBuilder],
|
||||||
) -> Result<Predicate> {
|
) -> Result<Predicate> {
|
||||||
if args.len() > params.max_statement_args {
|
if args.len() > params.max_statement_args {
|
||||||
return Err(anyhow!(
|
return Err(Error::max_length(
|
||||||
"args.len {} is over the limit {}",
|
"args.len".to_string(),
|
||||||
args.len(),
|
args.len(),
|
||||||
params.max_statement_args
|
params.max_statement_args,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (args.len() + priv_args.len()) > params.max_custom_predicate_wildcards {
|
if (args.len() + priv_args.len()) > params.max_custom_predicate_wildcards {
|
||||||
return Err(anyhow!(
|
return Err(Error::max_length(
|
||||||
"wildcards.len {} is over the limit {}",
|
"wildcards.len".to_string(),
|
||||||
args.len() + priv_args.len(),
|
args.len() + priv_args.len(),
|
||||||
params.max_custom_predicate_wildcards
|
params.max_custom_predicate_wildcards,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
63
src/frontend/error.rs
Normal file
63
src/frontend/error.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
use std::{backtrace::Backtrace, fmt::Debug};
|
||||||
|
|
||||||
|
use crate::middleware::{DynError, Statement, StatementTmpl};
|
||||||
|
|
||||||
|
pub type Result<T, E = Error> = core::result::Result<T, E>;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum InnerError {
|
||||||
|
#[error("{0} {1} is over the limit {2}")]
|
||||||
|
MaxLength(String, usize, usize),
|
||||||
|
#[error("{0} doesn't match {1}")]
|
||||||
|
StatementsDontMatch(Statement, StatementTmpl),
|
||||||
|
#[error("invalid arguments to {0} operation")]
|
||||||
|
OpInvalidArgs(String),
|
||||||
|
// Other
|
||||||
|
#[error("{0}")]
|
||||||
|
Custom(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Inner: {inner}\n{backtrace}")]
|
||||||
|
Inner {
|
||||||
|
inner: Box<InnerError>,
|
||||||
|
backtrace: Box<Backtrace>,
|
||||||
|
},
|
||||||
|
#[error(transparent)]
|
||||||
|
Infallible(#[from] std::convert::Infallible),
|
||||||
|
#[error(transparent)]
|
||||||
|
Backend(#[from] Box<DynError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
Middleware(#[from] crate::middleware::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! new {
|
||||||
|
($inner:expr) => {
|
||||||
|
Error::Inner {
|
||||||
|
inner: Box::new($inner),
|
||||||
|
backtrace: Box::new(Backtrace::capture()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
use InnerError::*;
|
||||||
|
impl Error {
|
||||||
|
pub(crate) fn custom(s: impl Into<String>) -> Self {
|
||||||
|
new!(Custom(s.into()))
|
||||||
|
}
|
||||||
|
pub(crate) fn op_invalid_args(s: String) -> Self {
|
||||||
|
new!(OpInvalidArgs(s))
|
||||||
|
}
|
||||||
|
pub(crate) fn statements_dont_match(s0: Statement, s1: StatementTmpl) -> Self {
|
||||||
|
new!(StatementsDontMatch(s0, s1))
|
||||||
|
}
|
||||||
|
pub(crate) fn max_length(obj: String, found: usize, expect: usize) -> Self {
|
||||||
|
new!(MaxLength(obj, found, expect))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
use std::{collections::HashMap, convert::From, fmt};
|
use std::{collections::HashMap, convert::From, fmt};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -14,9 +13,11 @@ use crate::middleware::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod custom;
|
mod custom;
|
||||||
|
mod error;
|
||||||
mod operation;
|
mod operation;
|
||||||
mod serialization;
|
mod serialization;
|
||||||
pub use custom::*;
|
pub use custom::*;
|
||||||
|
pub use error::*;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
use serialization::*;
|
use serialization::*;
|
||||||
|
|
||||||
|
|
@ -101,7 +102,7 @@ impl SignedPod {
|
||||||
self.pod.id()
|
self.pod.id()
|
||||||
}
|
}
|
||||||
pub fn verify(&self) -> Result<()> {
|
pub fn verify(&self) -> Result<()> {
|
||||||
self.pod.verify()
|
self.pod.verify().map_err(Error::Backend)
|
||||||
}
|
}
|
||||||
pub fn kvs(&self) -> &HashMap<Key, Value> {
|
pub fn kvs(&self) -> &HashMap<Key, Value> {
|
||||||
&self.kvs
|
&self.kvs
|
||||||
|
|
@ -276,11 +277,17 @@ impl MainPodBuilder {
|
||||||
let container =
|
let container =
|
||||||
op.1.get(0)
|
op.1.get(0)
|
||||||
.and_then(|arg| arg.value())
|
.and_then(|arg| arg.value())
|
||||||
.ok_or(anyhow!("Invalid container argument for op {}.", op))?;
|
.ok_or(Error::custom(format!(
|
||||||
|
"Invalid container argument for op {}.",
|
||||||
|
op
|
||||||
|
)))?;
|
||||||
let key =
|
let key =
|
||||||
op.1.get(1)
|
op.1.get(1)
|
||||||
.and_then(|arg| arg.value())
|
.and_then(|arg| arg.value())
|
||||||
.ok_or(anyhow!("Invalid key argument for op {}.", op))?;
|
.ok_or(Error::custom(format!(
|
||||||
|
"Invalid key argument for op {}.",
|
||||||
|
op
|
||||||
|
)))?;
|
||||||
let proof = if op_type == &Native(ContainsFromEntries) {
|
let proof = if op_type == &Native(ContainsFromEntries) {
|
||||||
container.prove_existence(key)?.1
|
container.prove_existence(key)?.1
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -292,7 +299,7 @@ impl MainPodBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op(&mut self, public: bool, op: Operation) -> Result<Statement, anyhow::Error> {
|
fn op(&mut self, public: bool, op: Operation) -> Result<Statement> {
|
||||||
use NativeOperation::*;
|
use NativeOperation::*;
|
||||||
let mut op = Self::fill_in_aux(Self::lower_op(op))?;
|
let mut op = Self::fill_in_aux(Self::lower_op(op))?;
|
||||||
let Operation(op_type, ref mut args, _) = &mut op;
|
let Operation(op_type, ref mut args, _) = &mut op;
|
||||||
|
|
@ -301,7 +308,7 @@ impl MainPodBuilder {
|
||||||
// We are dealing with a copy here.
|
// We are dealing with a copy here.
|
||||||
match (args).first() {
|
match (args).first() {
|
||||||
Some(OperationArg::Statement(s)) if args.len() == 1 => Ok(s.predicate().clone()),
|
Some(OperationArg::Statement(s)) if args.len() == 1 => Ok(s.predicate().clone()),
|
||||||
_ => Err(anyhow!("Invalid arguments to copy operation: {:?}", args)),
|
_ => Err(Error::op_invalid_args("copy".to_string())),
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
@ -312,7 +319,7 @@ impl MainPodBuilder {
|
||||||
CopyStatement => match &args[0] {
|
CopyStatement => match &args[0] {
|
||||||
OperationArg::Statement(s) => s.args().clone(),
|
OperationArg::Statement(s) => s.args().clone(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!("Invalid arguments to copy operation: {}", op));
|
return Err(Error::op_invalid_args("copy".to_string()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
EqualFromEntries => self.op_args_entries(public, args)?,
|
EqualFromEntries => self.op_args_entries(public, args)?,
|
||||||
|
|
@ -331,14 +338,14 @@ impl MainPodBuilder {
|
||||||
if ak1 == ak2 {
|
if ak1 == ak2 {
|
||||||
vec![StatementArg::Key(ak0), StatementArg::Key(ak3)]
|
vec![StatementArg::Key(ak0), StatementArg::Key(ak3)]
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!(
|
return Err(Error::op_invalid_args(
|
||||||
"Invalid arguments to transitive equality operation"
|
"transitivity equality".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!(
|
return Err(Error::op_invalid_args(
|
||||||
"Invalid arguments to transitive equality operation"
|
"transitivity equality".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -348,7 +355,7 @@ impl MainPodBuilder {
|
||||||
vec![StatementArg::Key(ak0), StatementArg::Key(ak1)]
|
vec![StatementArg::Key(ak0), StatementArg::Key(ak1)]
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!("Invalid arguments to gt-to-neq operation"));
|
return Err(Error::op_invalid_args("gt-to-neq".to_string()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LtToNotEqual => match args[0].clone() {
|
LtToNotEqual => match args[0].clone() {
|
||||||
|
|
@ -356,7 +363,7 @@ impl MainPodBuilder {
|
||||||
vec![StatementArg::Key(ak0), StatementArg::Key(ak1)]
|
vec![StatementArg::Key(ak0), StatementArg::Key(ak1)]
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!("Invalid arguments to lt-to-neq operation"));
|
return Err(Error::op_invalid_args("lt-to-neq".to_string()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SumOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
SumOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
||||||
|
|
@ -375,11 +382,11 @@ impl MainPodBuilder {
|
||||||
StatementArg::Key(ak2),
|
StatementArg::Key(ak2),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!("Invalid arguments to sum-of operation"));
|
return Err(Error::op_invalid_args("sum-of".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!("Invalid arguments to sum-of operation"));
|
return Err(Error::op_invalid_args("sum-of".to_string()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ProductOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
ProductOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
||||||
|
|
@ -398,11 +405,11 @@ impl MainPodBuilder {
|
||||||
StatementArg::Key(ak2),
|
StatementArg::Key(ak2),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!("Invalid arguments to product-of operation"));
|
return Err(Error::op_invalid_args("product-of".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!("Invalid arguments to product-of operation"));
|
return Err(Error::op_invalid_args("product-of".to_string()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MaxOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
MaxOf => match (args[0].clone(), args[1].clone(), args[2].clone()) {
|
||||||
|
|
@ -421,11 +428,11 @@ impl MainPodBuilder {
|
||||||
StatementArg::Key(ak2),
|
StatementArg::Key(ak2),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!("Invalid arguments to max-of operation"));
|
return Err(Error::op_invalid_args("max-of".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow!("Invalid arguments to max-of operation"));
|
return Err(Error::op_invalid_args("max-of".to_string()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ContainsFromEntries => self.op_args_entries(public, args)?,
|
ContainsFromEntries => self.op_args_entries(public, args)?,
|
||||||
|
|
@ -441,17 +448,17 @@ impl MainPodBuilder {
|
||||||
OperationType::Custom(cpr) => {
|
OperationType::Custom(cpr) => {
|
||||||
let pred = &cpr.batch.predicates[cpr.index];
|
let pred = &cpr.batch.predicates[cpr.index];
|
||||||
if pred.statements.len() != args.len() {
|
if pred.statements.len() != args.len() {
|
||||||
return Err(anyhow!(
|
return Err(Error::custom(format!(
|
||||||
"Custom predicate operation needs {} statements but has {}.",
|
"Custom predicate operation needs {} statements but has {}.",
|
||||||
pred.statements.len(),
|
pred.statements.len(),
|
||||||
args.len()
|
args.len()
|
||||||
));
|
)));
|
||||||
}
|
}
|
||||||
// All args should be statements to be pattern matched against statement templates.
|
// All args should be statements to be pattern matched against statement templates.
|
||||||
let args = args.iter().map(
|
let args = args.iter().map(
|
||||||
|a| match a {
|
|a| match a {
|
||||||
OperationArg::Statement(s) => Ok(s.clone()),
|
OperationArg::Statement(s) => Ok(s.clone()),
|
||||||
_ => Err(anyhow!("Invalid argument {} to operation corresponding to custom predicate {:?}.", a, cpr))
|
_ => Err(Error::custom(format!("Invalid argument {} to operation corresponding to custom predicate {:?}.", a, cpr)))
|
||||||
}
|
}
|
||||||
).collect::<Result<Vec<_>>>()?;
|
).collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
|
|
@ -462,7 +469,7 @@ impl MainPodBuilder {
|
||||||
for (st_tmpl_arg, st_arg) in st_tmpl.args.iter().zip(&st_args) {
|
for (st_tmpl_arg, st_arg) in st_tmpl.args.iter().zip(&st_args) {
|
||||||
if !check_st_tmpl(st_tmpl_arg, st_arg, &mut wildcard_map) {
|
if !check_st_tmpl(st_tmpl_arg, st_arg, &mut wildcard_map) {
|
||||||
// TODO: Add wildcard_map in the error for better context
|
// TODO: Add wildcard_map in the error for better context
|
||||||
return Err(anyhow!("{} doesn't match {}", st, st_tmpl));
|
return Err(Error::statements_dont_match(st.clone(), st_tmpl.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -563,7 +570,11 @@ impl MainPodBuilder {
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.ok_or(anyhow!("Missing POD type information in POD: {:?}", pod))?;
|
.ok_or(Error::custom(format!(
|
||||||
|
// TODO use a specific Error
|
||||||
|
"Missing POD type information in POD: {:?}",
|
||||||
|
pod
|
||||||
|
)))?;
|
||||||
// Replace instances of `SELF` with the POD ID for consistency
|
// Replace instances of `SELF` with the POD ID for consistency
|
||||||
// with `pub_statements` method.
|
// with `pub_statements` method.
|
||||||
let public_statements = [type_statement]
|
let public_statements = [type_statement]
|
||||||
|
|
@ -676,7 +687,7 @@ impl MainPodCompiler {
|
||||||
op.1.iter()
|
op.1.iter()
|
||||||
.flat_map(|arg| self.compile_op_arg(arg))
|
.flat_map(|arg| self.compile_op_arg(arg))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
middleware::Operation::op(op.0.clone(), &mop_args, &op.2)
|
Ok(middleware::Operation::op(op.0.clone(), &mop_args, &op.2)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_st_op(&mut self, st: &Statement, op: &Operation, params: &Params) -> Result<()> {
|
fn compile_st_op(&mut self, st: &Statement, op: &Operation, params: &Params) -> Result<()> {
|
||||||
|
|
@ -684,11 +695,10 @@ impl MainPodCompiler {
|
||||||
let is_correct = middle_op.check(params, st)?;
|
let is_correct = middle_op.check(params, st)?;
|
||||||
if !is_correct {
|
if !is_correct {
|
||||||
// todo: improve error handling
|
// todo: improve error handling
|
||||||
Err(anyhow!(
|
Err(Error::custom(format!(
|
||||||
"Compile failed due to invalid deduction:\n {} ⇏ {}",
|
"Compile failed due to invalid deduction:\n {} ⇏ {}",
|
||||||
middle_op,
|
middle_op, st
|
||||||
st
|
)))
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
self.push_st_op(st.clone(), middle_op);
|
self.push_st_op(st.clone(), middle_op);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -822,11 +832,10 @@ pub mod tests {
|
||||||
if kvs == embedded_kvs {
|
if kvs == embedded_kvs {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!(
|
Err(Error::custom(format!(
|
||||||
"KVs {:?} do not agree with those embedded in the POD: {:?}",
|
"KVs {:?} do not agree with those embedded in the POD: {:?}",
|
||||||
kvs,
|
kvs, embedded_kvs
|
||||||
embedded_kvs
|
)))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::mock::{mainpod::MockMainPod, signedpod::MockSignedPod},
|
backends::plonky2::mock::{mainpod::MockMainPod, signedpod::MockSignedPod},
|
||||||
frontend::{MainPod, SignedPod, Statement},
|
frontend::{Error, MainPod, SignedPod, Statement},
|
||||||
middleware::{containers::Dictionary, Key, PodId, Value},
|
middleware::{containers::Dictionary, Key, PodId, Value},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -20,14 +20,14 @@ pub struct SignedPodHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<SignedPodHelper> for SignedPod {
|
impl TryFrom<SignedPodHelper> for SignedPod {
|
||||||
type Error = anyhow::Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(helper: SignedPodHelper) -> Result<SignedPod, Self::Error> {
|
fn try_from(helper: SignedPodHelper) -> Result<SignedPod, Self::Error> {
|
||||||
if helper.pod_class != "Signed" {
|
if helper.pod_class != "Signed" {
|
||||||
return Err(anyhow::anyhow!("pod_class is not Signed"));
|
return Err(Error::custom("pod_class is not Signed"));
|
||||||
}
|
}
|
||||||
if helper.pod_type != "Mock" {
|
if helper.pod_type != "Mock" {
|
||||||
return Err(anyhow::anyhow!("pod_type is not Mock"));
|
return Err(Error::custom("pod_type is not Mock"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let dict = Dictionary::new(helper.entries.clone())?.clone();
|
let dict = Dictionary::new(helper.entries.clone())?.clone();
|
||||||
|
|
@ -62,18 +62,18 @@ pub struct MainPodHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<MainPodHelper> for MainPod {
|
impl TryFrom<MainPodHelper> for MainPod {
|
||||||
type Error = anyhow::Error; // or you can create a custom error type
|
type Error = Error; // or you can create a custom error type
|
||||||
|
|
||||||
fn try_from(helper: MainPodHelper) -> Result<Self, Self::Error> {
|
fn try_from(helper: MainPodHelper) -> Result<Self, Self::Error> {
|
||||||
if helper.pod_class != "Main" {
|
if helper.pod_class != "Main" {
|
||||||
return Err(anyhow::anyhow!("pod_class is not Main"));
|
return Err(Error::custom("pod_class is not Main"));
|
||||||
}
|
}
|
||||||
if helper.pod_type != "Mock" {
|
if helper.pod_type != "Mock" {
|
||||||
return Err(anyhow::anyhow!("pod_type is not Mock"));
|
return Err(Error::custom("pod_type is not Mock"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let pod = MockMainPod::deserialize(helper.proof)
|
let pod = MockMainPod::deserialize(helper.proof)
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to deserialize proof: {}", e))?;
|
.map_err(|e| Error::custom(format!("Failed to deserialize proof: {}", e)))?;
|
||||||
|
|
||||||
Ok(MainPod {
|
Ok(MainPod {
|
||||||
pod: Box::new(pod),
|
pod: Box::new(pod),
|
||||||
|
|
@ -97,12 +97,10 @@ impl From<MainPod> for MainPodHelper {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
// Pretty assertions give nicer diffs between expected and actual values
|
// Pretty assertions give nicer diffs between expected and actual values
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use schemars::schema_for;
|
use schemars::schema_for;
|
||||||
|
|
||||||
// use schemars::generate::SchemaSettings;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::mock::{mainpod::MockProver, signedpod::MockSigner},
|
backends::plonky2::mock::{mainpod::MockProver, signedpod::MockSigner},
|
||||||
|
|
@ -110,7 +108,7 @@ mod tests {
|
||||||
eth_dos_pod_builder, eth_friend_signed_pod_builder, zu_kyc_pod_builder,
|
eth_dos_pod_builder, eth_friend_signed_pod_builder, zu_kyc_pod_builder,
|
||||||
zu_kyc_sign_pod_builders,
|
zu_kyc_sign_pod_builders,
|
||||||
},
|
},
|
||||||
frontend::SignedPodBuilder,
|
frontend::{Result, SignedPodBuilder},
|
||||||
middleware::{
|
middleware::{
|
||||||
self,
|
self,
|
||||||
containers::{Array, Set},
|
containers::{Array, Set},
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ use std::{
|
||||||
fmt,
|
fmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use hex::{FromHex, FromHexError};
|
use hex::{FromHex, FromHexError};
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
field::{
|
field::{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
//! This file implements the types defined at
|
||||||
|
//! https://0xparc.github.io/pod2/values.html#dictionary-array-set .
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
/// This file implements the types defined at
|
|
||||||
/// https://0xparc.github.io/pod2/values.html#dictionary-array-set .
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ use super::serialization::{ordered_map, ordered_set};
|
||||||
use crate::backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree};
|
use crate::backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree};
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::MAX_DEPTH,
|
constants::MAX_DEPTH,
|
||||||
middleware::{hash_value, Hash, Key, RawValue, Value, EMPTY_VALUE},
|
middleware::{hash_value, Error, Hash, Key, RawValue, Result, Value, EMPTY_VALUE},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Dictionary: the user original keys and values are hashed to be used in the leaf.
|
/// Dictionary: the user original keys and values are hashed to be used in the leaf.
|
||||||
|
|
@ -43,7 +43,7 @@ impl Dictionary {
|
||||||
pub fn get(&self, key: &Key) -> Result<&Value> {
|
pub fn get(&self, key: &Key) -> Result<&Value> {
|
||||||
self.kvs
|
self.kvs
|
||||||
.get(key)
|
.get(key)
|
||||||
.ok_or_else(|| anyhow!("key \"{}\" not found", key.name()))
|
.ok_or_else(|| Error::custom(format!("key \"{}\" not found", key.name())))
|
||||||
}
|
}
|
||||||
pub fn prove(&self, key: &Key) -> Result<(&Value, MerkleProof)> {
|
pub fn prove(&self, key: &Key) -> Result<(&Value, MerkleProof)> {
|
||||||
let (_, mtp) = self.mt.prove(&RawValue(key.hash().0))?;
|
let (_, mtp) = self.mt.prove(&RawValue(key.hash().0))?;
|
||||||
|
|
@ -51,15 +51,23 @@ impl Dictionary {
|
||||||
Ok((value, mtp))
|
Ok((value, mtp))
|
||||||
}
|
}
|
||||||
pub fn prove_nonexistence(&self, key: &Key) -> Result<MerkleProof> {
|
pub fn prove_nonexistence(&self, key: &Key) -> Result<MerkleProof> {
|
||||||
self.mt.prove_nonexistence(&RawValue(key.hash().0))
|
Ok(self.mt.prove_nonexistence(&RawValue(key.hash().0))?)
|
||||||
}
|
}
|
||||||
pub fn verify(root: Hash, proof: &MerkleProof, key: &Key, value: &Value) -> Result<()> {
|
pub fn verify(root: Hash, proof: &MerkleProof, key: &Key, value: &Value) -> Result<()> {
|
||||||
let key = RawValue(key.hash().0);
|
let key = RawValue(key.hash().0);
|
||||||
MerkleTree::verify(MAX_DEPTH, root, proof, &key, &value.raw())
|
Ok(MerkleTree::verify(
|
||||||
|
MAX_DEPTH,
|
||||||
|
root,
|
||||||
|
proof,
|
||||||
|
&key,
|
||||||
|
&value.raw(),
|
||||||
|
)?)
|
||||||
}
|
}
|
||||||
pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Key) -> Result<()> {
|
pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, key: &Key) -> Result<()> {
|
||||||
let key = RawValue(key.hash().0);
|
let key = RawValue(key.hash().0);
|
||||||
MerkleTree::verify_nonexistence(MAX_DEPTH, root, proof, &key)
|
Ok(MerkleTree::verify_nonexistence(
|
||||||
|
MAX_DEPTH, root, proof, &key,
|
||||||
|
)?)
|
||||||
}
|
}
|
||||||
// TODO: Rename to dict to be consistent maybe?
|
// TODO: Rename to dict to be consistent maybe?
|
||||||
pub fn kvs(&self) -> &HashMap<Key, Value> {
|
pub fn kvs(&self) -> &HashMap<Key, Value> {
|
||||||
|
|
@ -142,15 +150,26 @@ impl Set {
|
||||||
}
|
}
|
||||||
pub fn prove_nonexistence(&self, value: &Value) -> Result<MerkleProof> {
|
pub fn prove_nonexistence(&self, value: &Value) -> Result<MerkleProof> {
|
||||||
let h = hash_value(&value.raw());
|
let h = hash_value(&value.raw());
|
||||||
self.mt.prove_nonexistence(&RawValue::from(h))
|
Ok(self.mt.prove_nonexistence(&RawValue::from(h))?)
|
||||||
}
|
}
|
||||||
pub fn verify(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> {
|
pub fn verify(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> {
|
||||||
let h = hash_value(&value.raw());
|
let h = hash_value(&value.raw());
|
||||||
MerkleTree::verify(MAX_DEPTH, root, proof, &RawValue::from(h), &EMPTY_VALUE)
|
Ok(MerkleTree::verify(
|
||||||
|
MAX_DEPTH,
|
||||||
|
root,
|
||||||
|
proof,
|
||||||
|
&RawValue::from(h),
|
||||||
|
&EMPTY_VALUE,
|
||||||
|
)?)
|
||||||
}
|
}
|
||||||
pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> {
|
pub fn verify_nonexistence(root: Hash, proof: &MerkleProof, value: &Value) -> Result<()> {
|
||||||
let h = hash_value(&value.raw());
|
let h = hash_value(&value.raw());
|
||||||
MerkleTree::verify_nonexistence(MAX_DEPTH, root, proof, &RawValue::from(h))
|
Ok(MerkleTree::verify_nonexistence(
|
||||||
|
MAX_DEPTH,
|
||||||
|
root,
|
||||||
|
proof,
|
||||||
|
&RawValue::from(h),
|
||||||
|
)?)
|
||||||
}
|
}
|
||||||
pub fn set(&self) -> &HashSet<Value> {
|
pub fn set(&self) -> &HashSet<Value> {
|
||||||
&self.set
|
&self.set
|
||||||
|
|
@ -217,9 +236,9 @@ impl Array {
|
||||||
self.mt.root()
|
self.mt.root()
|
||||||
}
|
}
|
||||||
pub fn get(&self, i: usize) -> Result<&Value> {
|
pub fn get(&self, i: usize) -> Result<&Value> {
|
||||||
self.array
|
self.array.get(i).ok_or_else(|| {
|
||||||
.get(i)
|
Error::custom(format!("index {} out of bounds 0..{}", i, self.array.len()))
|
||||||
.ok_or_else(|| anyhow!("index {} out of bounds 0..{}", i, self.array.len()))
|
})
|
||||||
}
|
}
|
||||||
pub fn prove(&self, i: usize) -> Result<(&Value, MerkleProof)> {
|
pub fn prove(&self, i: usize) -> Result<(&Value, MerkleProof)> {
|
||||||
let (_, mtp) = self.mt.prove(&RawValue::from(i as i64))?;
|
let (_, mtp) = self.mt.prove(&RawValue::from(i as i64))?;
|
||||||
|
|
@ -227,13 +246,13 @@ impl Array {
|
||||||
Ok((value, mtp))
|
Ok((value, mtp))
|
||||||
}
|
}
|
||||||
pub fn verify(root: Hash, proof: &MerkleProof, i: usize, value: &Value) -> Result<()> {
|
pub fn verify(root: Hash, proof: &MerkleProof, i: usize, value: &Value) -> Result<()> {
|
||||||
MerkleTree::verify(
|
Ok(MerkleTree::verify(
|
||||||
MAX_DEPTH,
|
MAX_DEPTH,
|
||||||
root,
|
root,
|
||||||
proof,
|
proof,
|
||||||
&RawValue::from(i as i64),
|
&RawValue::from(i as i64),
|
||||||
&value.raw(),
|
&value.raw(),
|
||||||
)
|
)?)
|
||||||
}
|
}
|
||||||
pub fn array(&self) -> &[Value] {
|
pub fn array(&self) -> &[Value] {
|
||||||
&self.array
|
&self.array
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
use std::{fmt, iter, sync::Arc};
|
use std::{fmt, iter, sync::Arc};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
hash_fields, Hash, Key, NativePredicate, Params, ToFields, Value, F, HASH_SIZE,
|
hash_fields, Error, Hash, Key, NativePredicate, Params, Result, ToFields, Value, F, HASH_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
|
@ -217,7 +216,11 @@ impl CustomPredicate {
|
||||||
args_len: usize,
|
args_len: usize,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
if statements.len() > params.max_custom_predicate_arity {
|
if statements.len() > params.max_custom_predicate_arity {
|
||||||
return Err(anyhow!("Custom predicate depends on too many statements"));
|
return Err(Error::max_length(
|
||||||
|
"statements.len".to_string(),
|
||||||
|
statements.len(),
|
||||||
|
params.max_custom_predicate_arity,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
@ -394,7 +397,6 @@ impl fmt::Display for Predicate {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{array, sync::Arc};
|
use std::{array, sync::Arc};
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
71
src/middleware/error.rs
Normal file
71
src/middleware/error.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
//! middleware errors
|
||||||
|
|
||||||
|
use std::{backtrace::Backtrace, fmt::Debug};
|
||||||
|
|
||||||
|
use crate::middleware::{Operation, Statement, StatementArg};
|
||||||
|
|
||||||
|
pub type Result<T, E = Error> = core::result::Result<T, E>;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum MiddlewareInnerError {
|
||||||
|
#[error("incorrect statement args")]
|
||||||
|
IncorrectStatementArgs,
|
||||||
|
#[error("invalid deduction: {0:?} ⇏ {1:#}")]
|
||||||
|
InvalidDeduction(Operation, Statement),
|
||||||
|
#[error("statement argument {0:?} should be a {1}")]
|
||||||
|
InvalidStatementArg(StatementArg, String),
|
||||||
|
#[error("{0} {1} is over the limit {2}")]
|
||||||
|
MaxLength(String, usize, usize),
|
||||||
|
#[error("{0} amount of {1} should be {1} but it's {2}")]
|
||||||
|
DiffAmount(String, String, usize, usize),
|
||||||
|
// Other
|
||||||
|
#[error("{0}")]
|
||||||
|
Custom(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Inner: {inner}\n{backtrace}")]
|
||||||
|
Inner {
|
||||||
|
inner: Box<MiddlewareInnerError>,
|
||||||
|
backtrace: Box<Backtrace>,
|
||||||
|
},
|
||||||
|
#[error(transparent)]
|
||||||
|
Tree(#[from] crate::backends::plonky2::primitives::merkletree::error::TreeError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! new {
|
||||||
|
($inner:expr) => {
|
||||||
|
Error::Inner {
|
||||||
|
inner: Box::new($inner),
|
||||||
|
backtrace: Box::new(Backtrace::capture()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
use MiddlewareInnerError::*;
|
||||||
|
impl Error {
|
||||||
|
pub(crate) fn incorrect_statements_args() -> Self {
|
||||||
|
new!(IncorrectStatementArgs)
|
||||||
|
}
|
||||||
|
pub(crate) fn invalid_deduction(op: Operation, st: Statement) -> Self {
|
||||||
|
new!(InvalidDeduction(op, st))
|
||||||
|
}
|
||||||
|
pub(crate) fn invalid_statement_arg(st_arg: StatementArg, v: String) -> Self {
|
||||||
|
new!(InvalidStatementArg(st_arg, v))
|
||||||
|
}
|
||||||
|
pub(crate) fn max_length(obj: String, found: usize, expect: usize) -> Self {
|
||||||
|
new!(MaxLength(obj, found, expect))
|
||||||
|
}
|
||||||
|
pub(crate) fn diff_amount(obj: String, unit: String, expect: usize, found: usize) -> Self {
|
||||||
|
new!(DiffAmount(obj, unit, expect, found))
|
||||||
|
}
|
||||||
|
pub(crate) fn custom(s: String) -> Self {
|
||||||
|
new!(Custom(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,21 +8,21 @@ use std::{
|
||||||
hash,
|
hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use containers::{Array, Dictionary, Set};
|
use containers::{Array, Dictionary, Set};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub mod containers;
|
pub mod containers;
|
||||||
mod custom;
|
mod custom;
|
||||||
|
mod error;
|
||||||
mod operation;
|
mod operation;
|
||||||
pub mod serialization;
|
pub mod serialization;
|
||||||
mod statement;
|
mod statement;
|
||||||
use std::{any::Any, collections::HashMap, fmt};
|
use std::{any::Any, collections::HashMap, fmt};
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
pub use basetypes::*;
|
pub use basetypes::*;
|
||||||
pub use custom::*;
|
pub use custom::*;
|
||||||
use dyn_clone::DynClone;
|
use dyn_clone::DynClone;
|
||||||
|
pub use error::*;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
use serialization::*;
|
use serialization::*;
|
||||||
pub use statement::*;
|
pub use statement::*;
|
||||||
|
|
@ -126,22 +126,25 @@ impl From<PodType> for TypedValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&TypedValue> for i64 {
|
impl TryFrom<&TypedValue> for i64 {
|
||||||
type Error = anyhow::Error;
|
type Error = Error;
|
||||||
fn try_from(v: &TypedValue) -> std::result::Result<Self, Self::Error> {
|
fn try_from(v: &TypedValue) -> std::result::Result<Self, Self::Error> {
|
||||||
if let TypedValue::Int(n) = v {
|
if let TypedValue::Int(n) = v {
|
||||||
Ok(*n)
|
Ok(*n)
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Value not an int"))
|
Err(Error::custom("Value not an int".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<TypedValue> for Key {
|
impl TryFrom<TypedValue> for Key {
|
||||||
type Error = anyhow::Error;
|
type Error = Error;
|
||||||
fn try_from(tv: TypedValue) -> Result<Self> {
|
fn try_from(tv: TypedValue) -> Result<Self> {
|
||||||
match tv {
|
match tv {
|
||||||
TypedValue::String(s) => Ok(Key::new(s)),
|
TypedValue::String(s) => Ok(Key::new(s)),
|
||||||
_ => Err(anyhow!("Value {} cannot be converted to a key.", tv)),
|
_ => Err(Error::custom(format!(
|
||||||
|
"Value {} cannot be converted to a key.",
|
||||||
|
tv
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -367,20 +370,31 @@ impl Value {
|
||||||
match &self.typed() {
|
match &self.typed() {
|
||||||
TypedValue::Array(a) => match key.typed() {
|
TypedValue::Array(a) => match key.typed() {
|
||||||
TypedValue::Int(i) if i >= &0 => a.prove((*i) as usize),
|
TypedValue::Int(i) if i >= &0 => a.prove((*i) as usize),
|
||||||
_ => Err(anyhow!("Invalid key {} for container {}.", key, self))?,
|
_ => Err(Error::custom(format!(
|
||||||
|
"Invalid key {} for container {}.",
|
||||||
|
key, self
|
||||||
|
)))?,
|
||||||
},
|
},
|
||||||
TypedValue::Dictionary(d) => d.prove(&key.typed().clone().try_into()?),
|
TypedValue::Dictionary(d) => d.prove(&key.typed().clone().try_into()?),
|
||||||
TypedValue::Set(s) => Ok((key, s.prove(key)?)),
|
TypedValue::Set(s) => Ok((key, s.prove(key)?)),
|
||||||
_ => Err(anyhow!("Invalid container value {}", self.typed())),
|
_ => Err(Error::custom(format!(
|
||||||
|
"Invalid container value {}",
|
||||||
|
self.typed()
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Determines Merkle non-existence proof for `key` in `self` (if applicable).
|
/// Determines Merkle non-existence proof for `key` in `self` (if applicable).
|
||||||
pub(crate) fn prove_nonexistence<'a>(&'a self, key: &'a Value) -> Result<MerkleProof> {
|
pub(crate) fn prove_nonexistence<'a>(&'a self, key: &'a Value) -> Result<MerkleProof> {
|
||||||
match &self.typed() {
|
match &self.typed() {
|
||||||
TypedValue::Array(_) => Err(anyhow!("Arrays do not support `NotContains` operation.")),
|
TypedValue::Array(_) => Err(Error::custom(
|
||||||
|
"Arrays do not support `NotContains` operation.".to_string(),
|
||||||
|
)),
|
||||||
TypedValue::Dictionary(d) => d.prove_nonexistence(&key.typed().clone().try_into()?),
|
TypedValue::Dictionary(d) => d.prove_nonexistence(&key.typed().clone().try_into()?),
|
||||||
TypedValue::Set(s) => s.prove_nonexistence(key),
|
TypedValue::Set(s) => s.prove_nonexistence(key),
|
||||||
_ => Err(anyhow!("Invalid container value {}", self.typed())),
|
_ => Err(Error::custom(format!(
|
||||||
|
"Invalid container value {}",
|
||||||
|
self.typed()
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -654,8 +668,10 @@ impl Params {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type DynError = dyn std::error::Error + Send + Sync;
|
||||||
|
|
||||||
pub trait Pod: fmt::Debug + DynClone + Any {
|
pub trait Pod: fmt::Debug + DynClone + Any {
|
||||||
fn verify(&self) -> Result<()>;
|
fn verify(&self) -> Result<(), Box<DynError>>;
|
||||||
fn id(&self) -> PodId;
|
fn id(&self) -> PodId;
|
||||||
fn pub_statements(&self) -> Vec<Statement>;
|
fn pub_statements(&self) -> Vec<Statement>;
|
||||||
/// Extract key-values from ValueOf public statements
|
/// Extract key-values from ValueOf public statements
|
||||||
|
|
@ -683,7 +699,11 @@ pub trait Pod: fmt::Debug + DynClone + Any {
|
||||||
dyn_clone::clone_trait_object!(Pod);
|
dyn_clone::clone_trait_object!(Pod);
|
||||||
|
|
||||||
pub trait PodSigner {
|
pub trait PodSigner {
|
||||||
fn sign(&mut self, params: &Params, kvs: &HashMap<Key, Value>) -> Result<Box<dyn Pod>>;
|
fn sign(
|
||||||
|
&mut self,
|
||||||
|
params: &Params,
|
||||||
|
kvs: &HashMap<Key, Value>,
|
||||||
|
) -> Result<Box<dyn Pod>, Box<DynError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is a filler type that fulfills the Pod trait and always verifies. It's empty. This
|
/// This is a filler type that fulfills the Pod trait and always verifies. It's empty. This
|
||||||
|
|
@ -692,7 +712,7 @@ pub trait PodSigner {
|
||||||
pub struct NonePod {}
|
pub struct NonePod {}
|
||||||
|
|
||||||
impl Pod for NonePod {
|
impl Pod for NonePod {
|
||||||
fn verify(&self) -> Result<()> {
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
|
|
@ -718,7 +738,11 @@ pub struct MainPodInputs<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PodProver {
|
pub trait PodProver {
|
||||||
fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result<Box<dyn Pod>>;
|
fn prove(
|
||||||
|
&mut self,
|
||||||
|
params: &Params,
|
||||||
|
inputs: MainPodInputs,
|
||||||
|
) -> Result<Box<dyn Pod>, Box<DynError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToFields {
|
pub trait ToFields {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use std::{fmt, iter, sync::Arc};
|
use std::{fmt, iter, sync::Arc};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -8,9 +7,9 @@ use serde::{Deserialize, Serialize};
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::primitives::merkletree::MerkleProof,
|
backends::plonky2::primitives::merkletree::MerkleProof,
|
||||||
middleware::{
|
middleware::{
|
||||||
custom::KeyOrWildcard, AnchoredKey, CustomPredicateBatch, CustomPredicateRef,
|
custom::KeyOrWildcard, AnchoredKey, CustomPredicateBatch, CustomPredicateRef, Error,
|
||||||
NativePredicate, Params, Predicate, Statement, StatementArg, StatementTmplArg, ToFields,
|
NativePredicate, Params, Predicate, Result, Statement, StatementArg, StatementTmplArg,
|
||||||
Wildcard, WildcardValue, F, SELF,
|
ToFields, Wildcard, WildcardValue, F, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -253,11 +252,10 @@ impl Operation {
|
||||||
Self::ProductOf(s1, s2, s3)
|
Self::ProductOf(s1, s2, s3)
|
||||||
}
|
}
|
||||||
(NO::MaxOf, (Some(s1), Some(s2), Some(s3)), OA::None, 3) => Self::MaxOf(s1, s2, s3),
|
(NO::MaxOf, (Some(s1), Some(s2), Some(s3)), OA::None, 3) => Self::MaxOf(s1, s2, s3),
|
||||||
_ => Err(anyhow!(
|
_ => Err(Error::custom(format!(
|
||||||
"Ill-formed operation {:?} with arguments {:?}.",
|
"Ill-formed operation {:?} with arguments {:?}.",
|
||||||
op_code,
|
op_code, args
|
||||||
args
|
)))?,
|
||||||
))?,
|
|
||||||
},
|
},
|
||||||
OperationType::Custom(cpr) => Self::Custom(cpr, args.to_vec()),
|
OperationType::Custom(cpr) => Self::Custom(cpr, args.to_vec()),
|
||||||
})
|
})
|
||||||
|
|
@ -320,10 +318,9 @@ impl Operation {
|
||||||
{
|
{
|
||||||
check_custom_pred(params, batch, *index, args, s_args)
|
check_custom_pred(params, batch, *index, args, s_args)
|
||||||
}
|
}
|
||||||
_ => Err(anyhow!(
|
_ => Err(Error::invalid_deduction(
|
||||||
"Invalid deduction: {:?} ⇏ {:#}",
|
self.clone(),
|
||||||
self,
|
output_statement.clone(),
|
||||||
output_statement
|
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -386,17 +383,19 @@ fn check_custom_pred(
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let pred = &batch.predicates[index];
|
let pred = &batch.predicates[index];
|
||||||
if pred.statements.len() != args.len() {
|
if pred.statements.len() != args.len() {
|
||||||
return Err(anyhow!(
|
return Err(Error::diff_amount(
|
||||||
"Custom predicate operation needs {} statements but has {}.",
|
"custom predicate operation".to_string(),
|
||||||
|
"statements".to_string(),
|
||||||
pred.statements.len(),
|
pred.statements.len(),
|
||||||
args.len()
|
args.len(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if pred.args_len != s_args.len() {
|
if pred.args_len != s_args.len() {
|
||||||
return Err(anyhow!(
|
return Err(Error::diff_amount(
|
||||||
"Custom predicate statement needs {} args but has {}.",
|
"custom predicate statement".to_string(),
|
||||||
|
"args".to_string(),
|
||||||
pred.args_len,
|
pred.args_len,
|
||||||
s_args.len()
|
s_args.len(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
use std::{fmt, iter};
|
use std::{fmt, iter};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum_macros::FromRepr;
|
use strum_macros::FromRepr;
|
||||||
|
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
AnchoredKey, CustomPredicateRef, Key, Params, PodId, Predicate, RawValue, ToFields, Value, F,
|
AnchoredKey, CustomPredicateRef, Error, Key, Params, PodId, Predicate, RawValue, Result,
|
||||||
VALUE_SIZE,
|
ToFields, Value, F, VALUE_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Maybe store KEY_SIGNER and KEY_TYPE as Key with lazy_static
|
// TODO: Maybe store KEY_SIGNER and KEY_TYPE as Key with lazy_static
|
||||||
|
|
@ -152,7 +151,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::ValueOf(a0, v1))
|
Ok(Self::ValueOf(a0, v1))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::Equal) => {
|
Native(NativePredicate::Equal) => {
|
||||||
|
|
@ -161,7 +160,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::Equal(a0, a1))
|
Ok(Self::Equal(a0, a1))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::NotEqual) => {
|
Native(NativePredicate::NotEqual) => {
|
||||||
|
|
@ -170,7 +169,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::NotEqual(a0, a1))
|
Ok(Self::NotEqual(a0, a1))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::Gt) => {
|
Native(NativePredicate::Gt) => {
|
||||||
|
|
@ -179,7 +178,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::Gt(a0, a1))
|
Ok(Self::Gt(a0, a1))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::Lt) => {
|
Native(NativePredicate::Lt) => {
|
||||||
|
|
@ -188,7 +187,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::Lt(a0, a1))
|
Ok(Self::Lt(a0, a1))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::Contains) => {
|
Native(NativePredicate::Contains) => {
|
||||||
|
|
@ -197,7 +196,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::Contains(a0, a1, a2))
|
Ok(Self::Contains(a0, a1, a2))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::NotContains) => {
|
Native(NativePredicate::NotContains) => {
|
||||||
|
|
@ -206,7 +205,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::NotContains(a0, a1))
|
Ok(Self::NotContains(a0, a1))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::SumOf) => {
|
Native(NativePredicate::SumOf) => {
|
||||||
|
|
@ -215,7 +214,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::SumOf(a0, a1, a2))
|
Ok(Self::SumOf(a0, a1, a2))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::ProductOf) => {
|
Native(NativePredicate::ProductOf) => {
|
||||||
|
|
@ -224,7 +223,7 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::ProductOf(a0, a1, a2))
|
Ok(Self::ProductOf(a0, a1, a2))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(NativePredicate::MaxOf) => {
|
Native(NativePredicate::MaxOf) => {
|
||||||
|
|
@ -233,17 +232,17 @@ impl Statement {
|
||||||
{
|
{
|
||||||
Ok(Self::MaxOf(a0, a1, a2))
|
Ok(Self::MaxOf(a0, a1, a2))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Incorrect statement args"))
|
Err(Error::incorrect_statements_args())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Native(np) => Err(anyhow!("Predicate {:?} is syntax sugar", np)),
|
Native(np) => Err(Error::custom(format!("Predicate {:?} is syntax sugar", np))),
|
||||||
BatchSelf(_) => unreachable!(),
|
BatchSelf(_) => unreachable!(),
|
||||||
Custom(cpr) => {
|
Custom(cpr) => {
|
||||||
let v_args: Result<Vec<WildcardValue>> = args
|
let v_args: Result<Vec<WildcardValue>> = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| match x {
|
.map(|x| match x {
|
||||||
StatementArg::WildcardLiteral(v) => Ok(v.clone()),
|
StatementArg::WildcardLiteral(v) => Ok(v.clone()),
|
||||||
_ => Err(anyhow!("Incorrect statement args")),
|
_ => Err(Error::incorrect_statements_args()),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Ok(Self::Custom(cpr, v_args?))
|
Ok(Self::Custom(cpr, v_args?))
|
||||||
|
|
@ -302,13 +301,19 @@ impl StatementArg {
|
||||||
pub fn literal(&self) -> Result<Value> {
|
pub fn literal(&self) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
Self::Literal(value) => Ok(value.clone()),
|
Self::Literal(value) => Ok(value.clone()),
|
||||||
_ => Err(anyhow!("Statement argument {:?} is not a literal.", self)),
|
_ => Err(Error::invalid_statement_arg(
|
||||||
|
self.clone(),
|
||||||
|
"literal".to_string(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn key(&self) -> Result<AnchoredKey> {
|
pub fn key(&self) -> Result<AnchoredKey> {
|
||||||
match self {
|
match self {
|
||||||
Self::Key(ak) => Ok(ak.clone()),
|
Self::Key(ak) => Ok(ak.clone()),
|
||||||
_ => Err(anyhow!("Statement argument {:?} is not a key.", self)),
|
_ => Err(Error::invalid_statement_arg(
|
||||||
|
self.clone(),
|
||||||
|
"key".to_string(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue