Fe contains (#145)

* Contains should take three arguments (root, key, value)

* Add a test for frontend Dictionaries

* Separate frontend and middleware operations

* Make tests pass: add arg to contains

* Cargo fmt

* Merkleproof verify circuit (#143)

* merkletree: add keypath circuit

* merkletree-circuit: implement proof of existence verification in-circuit

* parametrize max_depth at the tree circuit

* Constrain selectors in-circuit

* implement merketree nonexistence proof circuit, and add edgecase tests

* add non-existence proofs documentation in the mdbook, mv EMPTY->EMPTY_VALUE & NULL->EMPTY_HASH, dependency clean and public exposure methods

* review comments, some extra polishing and add a test that expects wrong proofs to fail

* Add circuit to check only merkleproofs-of-existence

With this, the merkletree_circuit module offers two different circuits:
- `MerkleProofCircuit`: allows to verify both proofs of existence and proofs
non-existence with the same circuit.
- `MerkleProofExistenceCircuit`: allows to verify proofs of existence only.

In this way, if only proofs of existence are needed,
`MerkleProofExistenceCircuit` should be used, which requires less amount
of constraints than `MerkleProofCircuit`.

* Code review

---------

Co-authored-by: Ahmad <root@ahmadafuni.com>

* Towards Contains/NotContains in middleware and backend

* Fix build

* Adding error handling to deal with op compile introduce extra ops

* Incorporate Merkle proofs into MockMainPod

* Merkleproof verify circuit (#143)

* merkletree: add keypath circuit

* merkletree-circuit: implement proof of existence verification in-circuit

* parametrize max_depth at the tree circuit

* Constrain selectors in-circuit

* implement merketree nonexistence proof circuit, and add edgecase tests

* add non-existence proofs documentation in the mdbook, mv EMPTY->EMPTY_VALUE & NULL->EMPTY_HASH, dependency clean and public exposure methods

* review comments, some extra polishing and add a test that expects wrong proofs to fail

* Add circuit to check only merkleproofs-of-existence

With this, the merkletree_circuit module offers two different circuits:
- `MerkleProofCircuit`: allows to verify both proofs of existence and proofs
non-existence with the same circuit.
- `MerkleProofExistenceCircuit`: allows to verify proofs of existence only.

In this way, if only proofs of existence are needed,
`MerkleProofExistenceCircuit` should be used, which requires less amount
of constraints than `MerkleProofCircuit`.

* Code review

---------

Co-authored-by: Ahmad <root@ahmadafuni.com>

* Towards Contains/NotContains in middleware and backend

* Frontend compound types -- allow one frontend operation to produce multiple middleware statements (in progress)

* Incorporate Merkle proofs into MockMainPod

* Incorporate Merkle proof op arg into frontend

* Compile one statement to many, in progress

* Fix remaining tests

* Minor clean-up

* Oops I did a bunch of work in the middle of a rebase, committing

* Incorporate Merkle proof op arg into frontend

* still working on frontend compound types, refactor compile() to output multiple statements

* Contains statements for frontend types: code compiles

* Tests pass

* Examples use front-end compound types

* Remove old Contains and NotContains from frontend

* Add nin to typos

* Code review

---------

Co-authored-by: arnaucube <git@arnaucube.com>
Co-authored-by: Ahmad <root@ahmadafuni.com>
This commit is contained in:
tideofwords 2025-03-26 17:54:58 -07:00 committed by GitHub
parent d6033b7090
commit d00ff95f41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 789 additions and 162 deletions

View file

@ -1,7 +1,10 @@
use std::fmt;
use super::{SignedPod, Statement, Value};
use crate::middleware::OperationType;
use super::{NativePredicate, Predicate, SignedPod, Statement, Value};
use crate::{
backends::plonky2::primitives::merkletree::MerkleProof,
middleware::{self, OperationAux},
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OperationArg {
@ -69,7 +72,120 @@ impl<V: Into<Value>> From<(&str, V)> for OperationArg {
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Operation(pub OperationType, pub Vec<OperationArg>);
pub enum OperationType {
Native(NativeOperation),
Custom(middleware::CustomPredicateRef),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NativeOperation {
None = 0,
NewEntry = 1,
CopyStatement = 2,
EqualFromEntries = 3,
NotEqualFromEntries = 4,
GtFromEntries = 5,
LtFromEntries = 6,
TransitiveEqualFromStatements = 7,
GtToNotEqual = 8,
LtToNotEqual = 9,
SumOf = 13,
ProductOf = 14,
MaxOf = 15,
DictContainsFromEntries = 16,
DictNotContainsFromEntries = 17,
SetContainsFromEntries = 18,
SetNotContainsFromEntries = 19,
ArrayContainsFromEntries = 20,
}
impl TryFrom<OperationType> for middleware::OperationType {
type Error = anyhow::Error;
fn try_from(fe_ot: OperationType) -> Result<Self, Self::Error> {
type FeOT = OperationType;
type FeNO = NativeOperation;
type MwOT = middleware::OperationType;
type MwNO = middleware::NativeOperation;
let mw_ot = match fe_ot {
FeOT::Native(FeNO::None) => MwOT::Native(MwNO::None),
FeOT::Native(FeNO::NewEntry) => MwOT::Native(MwNO::NewEntry),
FeOT::Native(FeNO::CopyStatement) => MwOT::Native(MwNO::CopyStatement),
FeOT::Native(FeNO::EqualFromEntries) => MwOT::Native(MwNO::EqualFromEntries),
FeOT::Native(FeNO::NotEqualFromEntries) => MwOT::Native(MwNO::NotEqualFromEntries),
FeOT::Native(FeNO::GtFromEntries) => MwOT::Native(MwNO::GtFromEntries),
FeOT::Native(FeNO::LtFromEntries) => MwOT::Native(MwNO::LtFromEntries),
FeOT::Native(FeNO::TransitiveEqualFromStatements) => {
MwOT::Native(MwNO::TransitiveEqualFromStatements)
}
FeOT::Native(FeNO::GtToNotEqual) => MwOT::Native(MwNO::GtToNotEqual),
FeOT::Native(FeNO::LtToNotEqual) => MwOT::Native(MwNO::LtToNotEqual),
FeOT::Native(FeNO::SumOf) => MwOT::Native(MwNO::SumOf),
FeOT::Native(FeNO::ProductOf) => MwOT::Native(MwNO::ProductOf),
FeOT::Native(FeNO::MaxOf) => MwOT::Native(MwNO::MaxOf),
FeOT::Native(FeNO::DictContainsFromEntries) => MwOT::Native(MwNO::ContainsFromEntries),
FeOT::Native(FeNO::DictNotContainsFromEntries) => {
MwOT::Native(MwNO::NotContainsFromEntries)
}
FeOT::Native(FeNO::SetContainsFromEntries) => MwOT::Native(MwNO::ContainsFromEntries),
FeOT::Native(FeNO::SetNotContainsFromEntries) => {
MwOT::Native(MwNO::NotContainsFromEntries)
}
FeOT::Native(FeNO::ArrayContainsFromEntries) => MwOT::Native(MwNO::ContainsFromEntries),
FeOT::Custom(mw_cpr) => MwOT::Custom(mw_cpr),
};
Ok(mw_ot)
}
}
impl OperationType {
/// Gives the type of predicate that the operation will output, if known.
/// CopyStatement may output any predicate (it will match the statement copied),
/// so output_predicate returns None on CopyStatement.
pub fn output_predicate(&self) -> Option<Predicate> {
match self {
OperationType::Native(native_op) => match native_op {
NativeOperation::None => Some(Predicate::Native(NativePredicate::None)),
NativeOperation::NewEntry => Some(Predicate::Native(NativePredicate::ValueOf)),
NativeOperation::CopyStatement => None,
NativeOperation::EqualFromEntries => {
Some(Predicate::Native(NativePredicate::Equal))
}
NativeOperation::NotEqualFromEntries => {
Some(Predicate::Native(NativePredicate::NotEqual))
}
NativeOperation::GtFromEntries => Some(Predicate::Native(NativePredicate::Gt)),
NativeOperation::LtFromEntries => Some(Predicate::Native(NativePredicate::Lt)),
NativeOperation::TransitiveEqualFromStatements => {
Some(Predicate::Native(NativePredicate::Equal))
}
NativeOperation::GtToNotEqual => Some(Predicate::Native(NativePredicate::NotEqual)),
NativeOperation::LtToNotEqual => Some(Predicate::Native(NativePredicate::NotEqual)),
NativeOperation::SumOf => Some(Predicate::Native(NativePredicate::SumOf)),
NativeOperation::ProductOf => Some(Predicate::Native(NativePredicate::ProductOf)),
NativeOperation::MaxOf => Some(Predicate::Native(NativePredicate::MaxOf)),
NativeOperation::DictContainsFromEntries => {
Some(Predicate::Native(NativePredicate::DictContains))
}
NativeOperation::DictNotContainsFromEntries => {
Some(Predicate::Native(NativePredicate::DictNotContains))
}
NativeOperation::SetContainsFromEntries => {
Some(Predicate::Native(NativePredicate::SetContains))
}
NativeOperation::SetNotContainsFromEntries => {
Some(Predicate::Native(NativePredicate::SetNotContains))
}
NativeOperation::ArrayContainsFromEntries => {
Some(Predicate::Native(NativePredicate::ArrayContains))
}
},
OperationType::Custom(cpr) => Some(Predicate::Custom(cpr.clone())),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Operation(pub OperationType, pub Vec<OperationArg>, pub OperationAux);
impl fmt::Display for Operation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {