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:
parent
656cae77e0
commit
1508dd6126
15 changed files with 1452 additions and 72 deletions
|
|
@ -240,6 +240,60 @@ impl MainPodBuilder {
|
|||
Operation(Native(LtFromEntries), vec![entry2, entry1], op.2)
|
||||
}),
|
||||
Native(GtToNotEqual) => Ok(Operation(Native(LtToNotEqual), op.1, op.2)),
|
||||
Native(DictInsertFromEntries) => {
|
||||
<[_; 4]>::try_from(op.1).map(|[new_dict, old_dict, key, value]| {
|
||||
Operation(
|
||||
Native(ContainerInsertFromEntries),
|
||||
vec![new_dict, old_dict, key, value],
|
||||
op.2,
|
||||
)
|
||||
})
|
||||
}
|
||||
Native(DictUpdateFromEntries) => {
|
||||
<[_; 4]>::try_from(op.1).map(|[new_dict, old_dict, key, value]| {
|
||||
Operation(
|
||||
Native(ContainerUpdateFromEntries),
|
||||
vec![new_dict, old_dict, key, value],
|
||||
op.2,
|
||||
)
|
||||
})
|
||||
}
|
||||
Native(DictDeleteFromEntries) => {
|
||||
<[_; 3]>::try_from(op.1).map(|[new_dict, old_dict, key]| {
|
||||
Operation(
|
||||
Native(ContainerDeleteFromEntries),
|
||||
vec![new_dict, old_dict, key],
|
||||
op.2,
|
||||
)
|
||||
})
|
||||
}
|
||||
Native(SetInsertFromEntries) => {
|
||||
<[_; 3]>::try_from(op.1).map(|[new_set, old_set, value]| {
|
||||
Operation(
|
||||
Native(ContainerInsertFromEntries),
|
||||
vec![new_set, old_set, value.clone(), value],
|
||||
op.2,
|
||||
)
|
||||
})
|
||||
}
|
||||
Native(SetDeleteFromEntries) => {
|
||||
<[_; 3]>::try_from(op.1).map(|[new_set, old_set, value]| {
|
||||
Operation(
|
||||
Native(ContainerDeleteFromEntries),
|
||||
vec![new_set, old_set, value],
|
||||
op.2,
|
||||
)
|
||||
})
|
||||
}
|
||||
Native(ArrayUpdateFromEntries) => {
|
||||
<[_; 4]>::try_from(op.1).map(|[new_arr, old_arr, i, value]| {
|
||||
Operation(
|
||||
Native(ContainerUpdateFromEntries),
|
||||
vec![new_arr, old_arr, i, value],
|
||||
op.2,
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => Ok(op),
|
||||
}
|
||||
.map_err(|_| {
|
||||
|
|
@ -249,7 +303,10 @@ impl MainPodBuilder {
|
|||
|
||||
/// Fills in auxiliary data if necessary/possible.
|
||||
fn fill_in_aux(op: Operation) -> Result<Operation> {
|
||||
use NativeOperation::{ContainsFromEntries, NotContainsFromEntries};
|
||||
use NativeOperation::{
|
||||
ContainerDeleteFromEntries, ContainerInsertFromEntries, ContainerUpdateFromEntries,
|
||||
ContainsFromEntries, NotContainsFromEntries,
|
||||
};
|
||||
use OperationAux as OpAux;
|
||||
use OperationType::Native;
|
||||
|
||||
|
|
@ -279,6 +336,45 @@ impl MainPodBuilder {
|
|||
};
|
||||
Ok(Operation(op_type.clone(), op.1, OpAux::MerkleProof(proof)))
|
||||
}
|
||||
(Native(ContainerInsertFromEntries), OpAux::None)
|
||||
| (Native(ContainerUpdateFromEntries), OpAux::None)
|
||||
| (Native(ContainerDeleteFromEntries), OpAux::None) => {
|
||||
let old_container =
|
||||
op.1.get(1)
|
||||
.and_then(|arg| arg.value())
|
||||
.ok_or(Error::custom(format!(
|
||||
"Invalid container argument for op {}.",
|
||||
op
|
||||
)))?;
|
||||
let key =
|
||||
op.1.get(2)
|
||||
.and_then(|arg| arg.value())
|
||||
.ok_or(Error::custom(format!(
|
||||
"Invalid key argument for op {}.",
|
||||
op
|
||||
)))?;
|
||||
let value =
|
||||
op.1.get(3)
|
||||
.and_then(|arg| arg.value())
|
||||
.ok_or(Error::custom(format!(
|
||||
"Invalid key argument for op {}.",
|
||||
op
|
||||
)));
|
||||
let proof = match op_type {
|
||||
Native(ContainerInsertFromEntries) => {
|
||||
old_container.prove_insertion(key, value?)?
|
||||
}
|
||||
Native(ContainerUpdateFromEntries) => {
|
||||
old_container.prove_update(key, value?)?
|
||||
}
|
||||
_ => old_container.prove_deletion(key)?,
|
||||
};
|
||||
Ok(Operation(
|
||||
op_type.clone(),
|
||||
op.1,
|
||||
OpAux::MerkleTreeStateTransitionProof(proof),
|
||||
))
|
||||
}
|
||||
_ => Ok(op),
|
||||
}
|
||||
}
|
||||
|
|
@ -405,6 +501,29 @@ impl MainPodBuilder {
|
|||
return Err(native_arg_error());
|
||||
}
|
||||
}
|
||||
(ContainerInsertFromEntries, &[a1, a2, a3, a4]) => {
|
||||
let (r1, _v1) = a1.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r2, _v2) = a2.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r3, _v3) = a3.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r4, _v4) = a4.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
// TODO: validate proof
|
||||
Statement::ContainerInsert(r1, r2, r3, r4)
|
||||
}
|
||||
(ContainerUpdateFromEntries, &[a1, a2, a3, a4]) => {
|
||||
let (r1, _v1) = a1.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r2, _v2) = a2.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r3, _v3) = a3.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r4, _v4) = a4.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
// TODO: validate proof
|
||||
Statement::ContainerUpdate(r1, r2, r3, r4)
|
||||
}
|
||||
(ContainerDeleteFromEntries, &[a1, a2, a3]) => {
|
||||
let (r1, _v1) = a1.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r2, _v2) = a2.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
let (r3, _v3) = a3.value_and_ref().ok_or_else(native_arg_error)?;
|
||||
// TODO: validate proof
|
||||
Statement::ContainerDelete(r1, r2, r3)
|
||||
}
|
||||
(t, _) => {
|
||||
if t.is_syntactic_sugar() {
|
||||
return Err(Error::custom(format!(
|
||||
|
|
@ -741,7 +860,10 @@ pub mod tests {
|
|||
tickets_pod_full_flow, zu_kyc_pod_builder, zu_kyc_pod_request,
|
||||
zu_kyc_sign_pod_builders, EthDosHelper, MOCK_VD_SET,
|
||||
},
|
||||
middleware::{containers::Dictionary, Value},
|
||||
middleware::{
|
||||
containers::{Array, Dictionary, Set},
|
||||
Value,
|
||||
},
|
||||
};
|
||||
|
||||
// Check that frontend public statements agree with those
|
||||
|
|
@ -987,19 +1109,140 @@ pub mod tests {
|
|||
let st1 = builder.op(true, Operation::new_entry("key", "a")).unwrap();
|
||||
let st2 = builder.literal(false, Value::from(1)).unwrap();
|
||||
|
||||
builder
|
||||
.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::DictContainsFromEntries),
|
||||
// Vec<OperationArg>
|
||||
vec![
|
||||
OperationArg::Statement(st0),
|
||||
OperationArg::Statement(st1),
|
||||
OperationArg::Statement(st2),
|
||||
],
|
||||
OperationAux::MerkleProof(dict.prove(&Key::from("a")).unwrap().1),
|
||||
))
|
||||
.unwrap();
|
||||
builder.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::DictContainsFromEntries),
|
||||
// Vec<OperationArg>
|
||||
vec![
|
||||
OperationArg::Statement(st0.clone()),
|
||||
OperationArg::Statement(st1),
|
||||
OperationArg::Statement(st2),
|
||||
],
|
||||
OperationAux::MerkleProof(dict.prove(&Key::from("a")).unwrap().1),
|
||||
))?;
|
||||
|
||||
let mut new_dict = dict.clone();
|
||||
new_dict.insert(&Key::from("d"), &Value::from(4))?;
|
||||
|
||||
builder.pub_op(Operation(
|
||||
OperationType::Native(NativeOperation::DictInsertFromEntries),
|
||||
vec![
|
||||
Value::from(new_dict.clone()).into(),
|
||||
OperationArg::Statement(st0.clone()),
|
||||
"d".into(),
|
||||
4.into(),
|
||||
],
|
||||
OperationAux::None,
|
||||
))?;
|
||||
|
||||
let mut new_old_dict = new_dict.clone();
|
||||
new_old_dict.delete(&Key::from("d"))?;
|
||||
|
||||
assert_eq!(new_old_dict, dict);
|
||||
|
||||
builder.pub_op(Operation(
|
||||
OperationType::Native(NativeOperation::DictDeleteFromEntries),
|
||||
vec![
|
||||
OperationArg::Statement(st0.clone()),
|
||||
Value::from(new_dict).into(),
|
||||
"d".into(),
|
||||
],
|
||||
OperationAux::None,
|
||||
))?;
|
||||
|
||||
new_old_dict.update(&Key::from("c"), &55.into())?;
|
||||
|
||||
builder.pub_op(Operation(
|
||||
OperationType::Native(NativeOperation::DictUpdateFromEntries),
|
||||
vec![
|
||||
Value::from(new_old_dict).into(),
|
||||
OperationArg::Statement(st0.clone()),
|
||||
"c".into(),
|
||||
55.into(),
|
||||
],
|
||||
OperationAux::None,
|
||||
))?;
|
||||
|
||||
let main_prover = MockProver {};
|
||||
let main_pod = builder.prove(&main_prover).unwrap();
|
||||
|
||||
println!("{}", main_pod);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sets() -> Result<()> {
|
||||
let params = Params::default();
|
||||
let vd_set = &*MOCK_VD_SET;
|
||||
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
||||
|
||||
let empty_set = Set::new(params.max_depth_mt_containers, [].into())?;
|
||||
|
||||
let mut set1 = empty_set.clone();
|
||||
set1.insert(&1.into())?;
|
||||
|
||||
let mut set2 = set1.clone();
|
||||
set2.delete(&1.into())?;
|
||||
|
||||
assert_eq!(set2, empty_set);
|
||||
|
||||
builder.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::SetInsertFromEntries),
|
||||
// Vec<OperationArg>
|
||||
vec![
|
||||
Value::from(set1.clone()).into(),
|
||||
Value::from(empty_set.clone()).into(),
|
||||
1.into(),
|
||||
],
|
||||
OperationAux::None,
|
||||
))?;
|
||||
|
||||
builder.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::SetDeleteFromEntries),
|
||||
// Vec<OperationArg>
|
||||
vec![
|
||||
Value::from(empty_set.clone()).into(),
|
||||
Value::from(set1.clone()).into(),
|
||||
1.into(),
|
||||
],
|
||||
OperationAux::None,
|
||||
))?;
|
||||
|
||||
let main_prover = MockProver {};
|
||||
let main_pod = builder.prove(&main_prover).unwrap();
|
||||
|
||||
println!("{}", main_pod);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arrays() -> Result<()> {
|
||||
let params = Params::default();
|
||||
let vd_set = &*MOCK_VD_SET;
|
||||
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
||||
|
||||
let array1 = Array::new(params.max_depth_mt_containers, [1.into()].into())?;
|
||||
|
||||
let mut array2 = array1.clone();
|
||||
array2.update(0, &5.into())?;
|
||||
|
||||
builder.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::ArrayUpdateFromEntries),
|
||||
// Vec<OperationArg>
|
||||
vec![
|
||||
Value::from(array2.clone()).into(),
|
||||
Value::from(array1.clone()).into(),
|
||||
0.into(),
|
||||
5.into(),
|
||||
],
|
||||
OperationAux::None,
|
||||
))?;
|
||||
|
||||
let main_prover = MockProver {};
|
||||
let main_pod = builder.prove(&main_prover).unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,21 @@ macro_rules! op_impl_oa {
|
|||
)
|
||||
}
|
||||
};
|
||||
|
||||
($fn_name: ident, $op_name: ident, 4) => {
|
||||
pub fn $fn_name(
|
||||
a1: impl Into<OperationArg>,
|
||||
a2: impl Into<OperationArg>,
|
||||
a3: impl Into<OperationArg>,
|
||||
a4: impl Into<OperationArg>,
|
||||
) -> Self {
|
||||
Self(
|
||||
OperationType::Native(NativeOperation::$op_name),
|
||||
vec![a1.into(), a2.into(), a3.into(), a4.into()],
|
||||
OperationAux::None,
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! op_impl_st {
|
||||
|
|
@ -201,4 +216,10 @@ impl Operation {
|
|||
op_impl_oa!(set_not_contains, SetNotContainsFromEntries, 2);
|
||||
op_impl_oa!(array_contains, ArrayContainsFromEntries, 3);
|
||||
op_impl_oa!(public_key_of, PublicKeyOf, 2);
|
||||
op_impl_oa!(dict_insert, DictInsertFromEntries, 4);
|
||||
op_impl_oa!(dict_update, DictUpdateFromEntries, 4);
|
||||
op_impl_oa!(dict_delete, DictDeleteFromEntries, 3);
|
||||
op_impl_oa!(set_insert, SetInsertFromEntries, 3);
|
||||
op_impl_oa!(set_delete, SetDeleteFromEntries, 3);
|
||||
op_impl_oa!(array_update, ArrayUpdateFromEntries, 4);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue