feat: add container update ops (#390)

* Add container update ops

* Update src/middleware/operation.rs

Co-authored-by: Eduard S. <eduardsanou@posteo.net>

* Update src/backends/plonky2/mainpod/mod.rs

Co-authored-by: Eduard S. <eduardsanou@posteo.net>

* Code review

---------

Co-authored-by: Eduard S. <eduardsanou@posteo.net>
This commit is contained in:
Ahmad Afuni 2025-08-13 06:34:45 +10:00 committed by GitHub
parent 656cae77e0
commit 1508dd6126
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 1452 additions and 72 deletions

View file

@ -19,7 +19,10 @@ use crate::{
error::{Error, Result},
hash_common_data,
mock::emptypod::MockEmptyPod,
primitives::{ec::schnorr::SecretKey, merkletree::MerkleClaimAndProof},
primitives::{
ec::schnorr::SecretKey,
merkletree::{MerkleClaimAndProof, MerkleTreeStateTransitionProof},
},
recursion::{
hash_verifier_data, prove_rec_circuit, RecursiveCircuit, RecursiveCircuitTarget,
},
@ -173,6 +176,33 @@ pub(crate) fn extract_merkle_proofs(
Ok(table)
}
/// Extracts Merkle state transition proofs from container update ops.
pub(crate) fn extract_merkle_tree_state_transition_proofs(
params: &Params,
aux_list: &mut [OperationAux],
operations: &[middleware::Operation],
) -> Result<Vec<MerkleTreeStateTransitionProof>> {
let mut table = Vec::new();
for (i, op) in operations.iter().enumerate() {
let pf = match op {
middleware::Operation::ContainerInsertFromEntries(_, _, _, _, pf)
| middleware::Operation::ContainerUpdateFromEntries(_, _, _, _, pf)
| middleware::Operation::ContainerDeleteFromEntries(_, _, _, pf) => pf.clone(),
_ => continue,
};
aux_list[i] = OperationAux::MerkleTreeStateTransitionProofIndex(table.len());
table.push(pf);
}
if table.len() > params.max_merkle_tree_state_transition_proofs_containers {
return Err(Error::custom(format!(
"The number of required Merkle proofs ({}) exceeds the maximum number ({}).",
table.len(),
params.max_merkle_tree_state_transition_proofs_containers
)));
}
Ok(table)
}
pub(crate) fn extract_public_key_of(
params: &Params,
aux_list: &mut [OperationAux],
@ -471,6 +501,9 @@ impl PodProver for Prover {
let public_key_of_sks =
extract_public_key_of(params, &mut aux_list, inputs.operations, inputs.statements)?;
let merkle_tree_state_transition_proofs =
extract_merkle_tree_state_transition_proofs(params, &mut aux_list, inputs.operations)?;
let (statements, public_statements) = layout_statements(params, false, &inputs)?;
let operations = process_private_statements_operations(
params,
@ -513,6 +546,7 @@ impl PodProver for Prover {
operations,
merkle_proofs,
public_key_of_sks,
merkle_tree_state_transition_proofs,
custom_predicate_batches,
custom_predicate_verifications,
};
@ -912,14 +946,15 @@ pub mod tests {
max_signed_pod_values: 2,
max_public_statements: 2,
num_public_statements_id: 4,
max_statement_args: 3,
max_operation_args: 3,
max_statement_args: 4,
max_operation_args: 4,
max_custom_predicate_batches: 2,
max_custom_predicate_verifications: 2,
max_custom_predicate_arity: 2,
max_custom_predicate_wildcards: 3,
max_custom_batch_size: 2,
max_merkle_proofs_containers: 2,
max_merkle_tree_state_transition_proofs_containers: 2,
max_public_key_of: 2,
max_depth_mt_containers: 4,
max_depth_mt_vds: 6,
@ -979,13 +1014,14 @@ pub mod tests {
max_input_recursive_pods: 0,
max_statements: 9,
max_public_statements: 4,
max_statement_args: 3,
max_operation_args: 3,
max_statement_args: 4,
max_operation_args: 4,
max_custom_predicate_arity: 3,
max_custom_batch_size: 3,
max_custom_predicate_wildcards: 4,
max_custom_predicate_verifications: 2,
max_merkle_proofs_containers: 0,
max_merkle_tree_state_transition_proofs_containers: 0,
..Default::default()
};
println!("{:#?}", params);

View file

@ -6,7 +6,7 @@ use crate::{
backends::plonky2::{
error::{Error, Result},
mainpod::Statement,
primitives::merkletree::MerkleClaimAndProof,
primitives::merkletree::{MerkleClaimAndProof, MerkleTreeStateTransitionProof},
},
middleware::{self, OperationType, Params},
};
@ -35,6 +35,7 @@ pub enum OperationAux {
None,
MerkleProofIndex(usize),
PublicKeyOfIndex(usize),
MerkleTreeStateTransitionProofIndex(usize),
CustomPredVerifyIndex(usize),
}
@ -46,12 +47,17 @@ impl OperationAux {
fn table_offset_public_key_of(params: &Params) -> usize {
Self::table_offset_merkle_proof(params) + params.max_merkle_proofs_containers
}
fn table_offset_custom_pred_verify(params: &Params) -> usize {
fn table_offset_merkle_tree_state_transition_proof(params: &Params) -> usize {
Self::table_offset_public_key_of(params) + params.max_public_key_of
}
fn table_offset_custom_pred_verify(params: &Params) -> usize {
Self::table_offset_merkle_tree_state_transition_proof(params)
+ params.max_merkle_tree_state_transition_proofs_containers
}
pub(crate) fn table_size(params: &Params) -> usize {
1 + params.max_merkle_proofs_containers
+ params.max_public_key_of
+ params.max_merkle_tree_state_transition_proofs_containers
+ params.max_custom_predicate_verifications
}
pub fn table_index(&self, params: &Params) -> usize {
@ -59,6 +65,9 @@ impl OperationAux {
Self::None => 0,
Self::MerkleProofIndex(i) => Self::table_offset_merkle_proof(params) + *i,
Self::PublicKeyOfIndex(i) => Self::table_offset_public_key_of(params) + *i,
Self::MerkleTreeStateTransitionProofIndex(i) => {
Self::table_offset_merkle_tree_state_transition_proof(params) + *i
}
Self::CustomPredVerifyIndex(i) => Self::table_offset_custom_pred_verify(params) + *i,
}
}
@ -81,6 +90,7 @@ impl Operation {
&self,
statements: &[Statement],
merkle_proofs: &[MerkleClaimAndProof],
merkle_tree_state_transition_proofs: &[MerkleTreeStateTransitionProof],
) -> Result<crate::middleware::Operation> {
let deref_args = self
.1
@ -104,6 +114,17 @@ impl Operation {
.proof
.clone(),
),
OperationAux::MerkleTreeStateTransitionProofIndex(i) => {
crate::middleware::OperationAux::MerkleTreeStateTransitionProof(
merkle_tree_state_transition_proofs
.get(i)
.ok_or(Error::custom(format!(
"Missing Merkle state transition proof index {}",
i
)))?
.clone(),
)
}
OperationAux::PublicKeyOfIndex(_) => crate::middleware::OperationAux::None,
};
Ok(middleware::Operation::op(
@ -133,6 +154,9 @@ impl fmt::Display for Operation {
OperationAux::MerkleProofIndex(i) => write!(f, " merkle_proof_{:02}", i)?,
OperationAux::CustomPredVerifyIndex(i) => write!(f, " custom_pred_verify_{:02}", i)?,
OperationAux::PublicKeyOfIndex(i) => write!(f, " public_key_of_{:02}", i)?,
OperationAux::MerkleTreeStateTransitionProofIndex(i) => {
write!(f, " merkle_tree_state_transition_proof_{:02}", i)?
}
}
Ok(())
}

View file

@ -74,6 +74,21 @@ impl TryFrom<Statement> for middleware::Statement {
S::HashOf(a1.try_into()?, a2.try_into()?, a3.try_into()?)
}
(NP::PublicKeyOf, &[a1, a2]) => S::PublicKeyOf(a1.try_into()?, a2.try_into()?),
(NP::ContainerInsert, &[a1, a2, a3, a4]) => S::ContainerInsert(
a1.try_into()?,
a2.try_into()?,
a3.try_into()?,
a4.try_into()?,
),
(NP::ContainerUpdate, &[a1, a2, a3, a4]) => S::ContainerUpdate(
a1.try_into()?,
a2.try_into()?,
a3.try_into()?,
a4.try_into()?,
),
(NP::ContainerDelete, &[a1, a2, a3]) => {
S::ContainerDelete(a1.try_into()?, a2.try_into()?, a3.try_into()?)
}
_ => Err(Error::custom(format!(
"Ill-formed statement expression {:?}",
s