Support mixed depth container merkle proofs (#508)
Some checks failed
Rust Build with features / Rust tests (push) Has been cancelled
Clippy Check / Rust formatting (push) Has been cancelled
Publish MainPod circuit info / Update Wiki with new MainPod circuit info (push) Has been cancelled
Check mdbook compilation / compile (push) Has been cancelled
Publish mdbook / build (push) Has been cancelled
Rustfmt Check / Rust formatting (push) Has been cancelled
Rust Tests / Rust tests (push) Has been cancelled
typos / Spell Check with Typos (push) Has been cancelled
Publish mdbook / deploy (push) Has been cancelled
Some checks failed
Rust Build with features / Rust tests (push) Has been cancelled
Clippy Check / Rust formatting (push) Has been cancelled
Publish MainPod circuit info / Update Wiki with new MainPod circuit info (push) Has been cancelled
Check mdbook compilation / compile (push) Has been cancelled
Publish mdbook / build (push) Has been cancelled
Rustfmt Check / Rust formatting (push) Has been cancelled
Rust Tests / Rust tests (push) Has been cancelled
typos / Spell Check with Typos (push) Has been cancelled
Publish mdbook / deploy (push) Has been cancelled
* remove enabled flag from merkle tree proofs * add small existence mpt proofs in MainPod * refactor params, add small transition proofs * complete * fix edge case in vdset * fix: use existence only proof for vdset * use consistent order for aux table
This commit is contained in:
parent
111b132a00
commit
5e3ac9a101
12 changed files with 2366 additions and 2189 deletions
|
|
@ -51,7 +51,7 @@ use crate::{
|
|||
mainpod::cache_get_rec_main_pod_verifier_circuit_data,
|
||||
primitives::merkletree::MerkleClaimAndProof,
|
||||
},
|
||||
middleware::{containers::Array, Hash, Params, RawValue, Result, Value},
|
||||
middleware::{containers::Array, Hash, Params, RawValue, Result, Value, EMPTY_HASH},
|
||||
};
|
||||
|
||||
pub static DEFAULT_VD_LIST: LazyLock<Vec<VerifierOnlyCircuitData>> = LazyLock::new(|| {
|
||||
|
|
@ -95,6 +95,12 @@ impl Eq for VDSet {}
|
|||
|
||||
impl VDSet {
|
||||
fn new_from_vds_hashes(mut vds_hashes: Vec<Hash>) -> Self {
|
||||
// If vds_hashes is empty we add an zero entry to be used as padding when verifying merkle
|
||||
// proofs of inclusion in the vds set. This zero entry can't be abused because no circuit
|
||||
// exists with a vds_hash = 0.
|
||||
if vds_hashes.is_empty() {
|
||||
vds_hashes.push(EMPTY_HASH);
|
||||
}
|
||||
// before using the hash values, sort them, so that each set of
|
||||
// verifier_datas gets the same VDSet root
|
||||
vds_hashes.sort();
|
||||
|
|
@ -150,6 +156,9 @@ impl VDSet {
|
|||
))?
|
||||
.clone())
|
||||
}
|
||||
pub fn get_vds_proof_0(&self) -> MerkleClaimAndProof {
|
||||
self.proofs_map[&self.vds_hashes[0]].clone()
|
||||
}
|
||||
/// Returns true if the `verifier_data_hash` is in the set
|
||||
pub fn contains(&self, verifier_data_hash: HashOut) -> bool {
|
||||
self.proofs_map
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use crate::{
|
|||
mainpod::{Operation, OperationArg, OperationAux, Statement},
|
||||
primitives::merkletree::{
|
||||
verify_merkle_proof_circuit, MerkleClaimAndProof, MerkleClaimAndProofTarget,
|
||||
MerkleProof, MerkleTreeStateTransitionProofTarget,
|
||||
MerkleProof, MerkleProofExistenceTarget, MerkleTreeStateTransitionProofTarget,
|
||||
},
|
||||
},
|
||||
middleware::{
|
||||
|
|
@ -725,7 +725,6 @@ impl CustomPredicateInBatchTarget {
|
|||
let mtp =
|
||||
MerkleClaimAndProofTarget::new_virtual(Params::max_depth_custom_batch_mt(), builder);
|
||||
let _true = builder._true();
|
||||
builder.connect(_true.target, mtp.enabled.target);
|
||||
builder.connect(_true.target, mtp.existence.target);
|
||||
let zero = builder.constant(F(0));
|
||||
let key = ValueTarget {
|
||||
|
|
@ -763,7 +762,7 @@ impl CustomPredicateInBatchTarget {
|
|||
value: RawValue::from(hash_fields(&predicate.to_fields())),
|
||||
proof: mtp.clone(),
|
||||
};
|
||||
self.mtp.set_targets(pw, true, &mtp_claim)?;
|
||||
self.mtp.set_targets(pw, &mtp_claim)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -987,7 +986,6 @@ pub trait Flattenable {
|
|||
/// elsewhere.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MerkleClaimTarget {
|
||||
pub(crate) enabled: BoolTarget,
|
||||
pub(crate) root: HashOutTarget,
|
||||
pub(crate) key: ValueTarget,
|
||||
pub(crate) value: ValueTarget,
|
||||
|
|
@ -997,7 +995,6 @@ pub struct MerkleClaimTarget {
|
|||
impl From<MerkleClaimAndProofTarget> for MerkleClaimTarget {
|
||||
fn from(pf: MerkleClaimAndProofTarget) -> Self {
|
||||
Self {
|
||||
enabled: pf.enabled,
|
||||
root: pf.root,
|
||||
key: pf.key,
|
||||
value: pf.value,
|
||||
|
|
@ -1006,12 +1003,25 @@ impl From<MerkleClaimAndProofTarget> for MerkleClaimTarget {
|
|||
}
|
||||
}
|
||||
|
||||
impl MerkleClaimTarget {
|
||||
pub fn from_proof_existence(
|
||||
builder: &mut CircuitBuilder,
|
||||
pf: MerkleProofExistenceTarget,
|
||||
) -> Self {
|
||||
Self {
|
||||
root: pf.root,
|
||||
key: pf.key,
|
||||
value: pf.value,
|
||||
existence: builder._true(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// For the purpose of op verification, we need only look up the
|
||||
/// Merkle state transition claim rather than the Merkle state
|
||||
/// transition proof since it is verified elsewhere.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MerkleTreeStateTransitionClaimTarget {
|
||||
pub(crate) enabled: BoolTarget,
|
||||
pub(crate) op: Target,
|
||||
pub(crate) old_root: HashOutTarget,
|
||||
pub(crate) new_root: HashOutTarget,
|
||||
|
|
@ -1022,7 +1032,6 @@ pub struct MerkleTreeStateTransitionClaimTarget {
|
|||
impl From<MerkleTreeStateTransitionProofTarget> for MerkleTreeStateTransitionClaimTarget {
|
||||
fn from(pf: MerkleTreeStateTransitionProofTarget) -> Self {
|
||||
Self {
|
||||
enabled: pf.enabled,
|
||||
op: pf.op,
|
||||
old_root: pf.old_root,
|
||||
new_root: pf.new_root,
|
||||
|
|
@ -1063,7 +1072,6 @@ impl Flattenable for ValueTarget {
|
|||
impl Flattenable for MerkleClaimTarget {
|
||||
fn flatten(&self) -> Vec<Target> {
|
||||
[
|
||||
vec![self.enabled.target],
|
||||
self.root.elements.to_vec(),
|
||||
self.key.elements.to_vec(),
|
||||
self.value.elements.to_vec(),
|
||||
|
|
@ -1075,31 +1083,28 @@ impl Flattenable for MerkleClaimTarget {
|
|||
fn from_flattened(params: &Params, vs: &[Target]) -> Self {
|
||||
assert_eq!(vs.len(), Self::size(params));
|
||||
Self {
|
||||
enabled: BoolTarget::new_unsafe(vs[0]),
|
||||
root: HashOutTarget::from_vec(vs[1..1 + NUM_HASH_OUT_ELTS].to_vec()),
|
||||
key: ValueTarget::from_slice(
|
||||
&vs[1 + NUM_HASH_OUT_ELTS..1 + NUM_HASH_OUT_ELTS + VALUE_SIZE],
|
||||
),
|
||||
root: HashOutTarget::from_vec(vs[0..NUM_HASH_OUT_ELTS].to_vec()),
|
||||
key: ValueTarget::from_slice(&vs[NUM_HASH_OUT_ELTS..NUM_HASH_OUT_ELTS + VALUE_SIZE]),
|
||||
value: ValueTarget::from_slice(
|
||||
&vs[1 + NUM_HASH_OUT_ELTS + VALUE_SIZE..1 + NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE],
|
||||
&vs[NUM_HASH_OUT_ELTS + VALUE_SIZE..NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE],
|
||||
),
|
||||
existence: BoolTarget::new_unsafe(vs[1 + NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE]),
|
||||
existence: BoolTarget::new_unsafe(vs[NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE]),
|
||||
}
|
||||
}
|
||||
|
||||
fn size(params: &Params) -> usize {
|
||||
2 + HashOutTarget::size(params) + 2 * ValueTarget::size(params)
|
||||
HashOutTarget::size(params) + 2 * ValueTarget::size(params) + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl Flattenable for MerkleTreeStateTransitionClaimTarget {
|
||||
fn flatten(&self) -> Vec<Target> {
|
||||
[
|
||||
vec![self.enabled.target, self.op],
|
||||
self.old_root.elements.to_vec(),
|
||||
self.new_root.elements.to_vec(),
|
||||
self.op_key.elements.to_vec(),
|
||||
self.op_value.elements.to_vec(),
|
||||
vec![self.op],
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
|
|
@ -1107,24 +1112,22 @@ impl Flattenable for MerkleTreeStateTransitionClaimTarget {
|
|||
fn from_flattened(params: &Params, vs: &[Target]) -> Self {
|
||||
assert_eq!(vs.len(), Self::size(params));
|
||||
Self {
|
||||
enabled: BoolTarget::new_unsafe(vs[0]),
|
||||
op: vs[1],
|
||||
old_root: HashOutTarget::from_vec(vs[2..2 + NUM_HASH_OUT_ELTS].to_vec()),
|
||||
old_root: HashOutTarget::from_vec(vs[0..NUM_HASH_OUT_ELTS].to_vec()),
|
||||
new_root: HashOutTarget::from_vec(
|
||||
vs[2 + NUM_HASH_OUT_ELTS..2 * (1 + NUM_HASH_OUT_ELTS)].to_vec(),
|
||||
vs[NUM_HASH_OUT_ELTS..2 * NUM_HASH_OUT_ELTS].to_vec(),
|
||||
),
|
||||
op_key: ValueTarget::from_slice(
|
||||
&vs[2 * (1 + NUM_HASH_OUT_ELTS)..2 * (1 + NUM_HASH_OUT_ELTS) + VALUE_SIZE],
|
||||
&vs[2 * NUM_HASH_OUT_ELTS..2 * NUM_HASH_OUT_ELTS + VALUE_SIZE],
|
||||
),
|
||||
op_value: ValueTarget::from_slice(
|
||||
&vs[2 * (1 + NUM_HASH_OUT_ELTS) + VALUE_SIZE
|
||||
..2 * (1 + NUM_HASH_OUT_ELTS) + 2 * VALUE_SIZE],
|
||||
&vs[2 * NUM_HASH_OUT_ELTS + VALUE_SIZE..2 * NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE],
|
||||
),
|
||||
op: vs[2 * NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE],
|
||||
}
|
||||
}
|
||||
|
||||
fn size(params: &Params) -> usize {
|
||||
2 * (1 + HashOutTarget::size(params)) + 2 * ValueTarget::size(params)
|
||||
2 * HashOutTarget::size(params) + 2 * ValueTarget::size(params) + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
1707
src/backends/plonky2/circuits/mainpod/tests.rs
Normal file
1707
src/backends/plonky2/circuits/mainpod/tests.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -148,14 +148,20 @@ pub(crate) fn extract_custom_predicate_verifications(
|
|||
Ok(table)
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MerkleProofs {
|
||||
pub(crate) medium: Vec<MerkleClaimAndProof>,
|
||||
pub(crate) small: Vec<MerkleClaimAndProof>,
|
||||
}
|
||||
|
||||
/// Extracts Merkle proofs from Contains/NotContains ops.
|
||||
pub(crate) fn extract_merkle_proofs(
|
||||
params: &Params,
|
||||
aux_list: &mut [OperationAux],
|
||||
operations: &[middleware::Operation],
|
||||
statements: &[middleware::Statement],
|
||||
) -> Result<Vec<MerkleClaimAndProof>> {
|
||||
let mut table = Vec::new();
|
||||
) -> Result<MerkleProofs> {
|
||||
let mut tables = MerkleProofs::default();
|
||||
for (i, (op, st)) in operations.iter().zip(statements.iter()).enumerate() {
|
||||
let deduction_err = || MiddlewareError::invalid_deduction(op.clone(), st.clone());
|
||||
let (root, key, value, pf) = match (op, st) {
|
||||
|
|
@ -178,31 +184,42 @@ pub(crate) fn extract_merkle_proofs(
|
|||
}
|
||||
_ => continue,
|
||||
};
|
||||
aux_list[i] = OperationAux::MerkleProofIndex(table.len());
|
||||
table.push(MerkleClaimAndProof::new(
|
||||
Hash::from(root),
|
||||
key,
|
||||
value,
|
||||
pf.clone(),
|
||||
));
|
||||
let claim_proof = MerkleClaimAndProof::new(Hash::from(root), key, value, pf.clone());
|
||||
if pf.existence
|
||||
// TODO: Make sure there's no off-by-one error here
|
||||
&& pf.siblings.len() <= params.containers.max_depth_small
|
||||
&& tables.small.len() < params.containers.state.max_small
|
||||
{
|
||||
aux_list[i] = OperationAux::MerkleProofIndex(Size::Small, tables.small.len());
|
||||
tables.small.push(claim_proof);
|
||||
} else {
|
||||
aux_list[i] = OperationAux::MerkleProofIndex(Size::Medium, tables.medium.len());
|
||||
tables.medium.push(claim_proof);
|
||||
}
|
||||
if table.len() > params.max_merkle_proofs_containers {
|
||||
}
|
||||
if tables.medium.len() > params.containers.state.max_medium {
|
||||
return Err(Error::custom(format!(
|
||||
"The number of required Merkle proofs ({}) exceeds the maximum number ({}).",
|
||||
table.len(),
|
||||
params.max_merkle_proofs_containers
|
||||
tables.medium.len(),
|
||||
params.containers.state.max_medium
|
||||
)));
|
||||
}
|
||||
Ok(table)
|
||||
Ok(tables)
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MerkleTransitionProofs {
|
||||
pub(crate) medium: Vec<MerkleTreeStateTransitionProof>,
|
||||
pub(crate) small: Vec<MerkleTreeStateTransitionProof>,
|
||||
}
|
||||
|
||||
/// Extracts Merkle state transition proofs from container update ops.
|
||||
pub(crate) fn extract_merkle_tree_state_transition_proofs(
|
||||
pub(crate) fn extract_merkle_transition_proofs(
|
||||
params: &Params,
|
||||
aux_list: &mut [OperationAux],
|
||||
operations: &[middleware::Operation],
|
||||
) -> Result<Vec<MerkleTreeStateTransitionProof>> {
|
||||
let mut table = Vec::new();
|
||||
) -> Result<MerkleTransitionProofs> {
|
||||
let mut tables = MerkleTransitionProofs::default();
|
||||
for (i, op) in operations.iter().enumerate() {
|
||||
let pf = match op {
|
||||
middleware::Operation::ContainerInsertFromEntries(_, _, _, _, pf)
|
||||
|
|
@ -210,17 +227,27 @@ pub(crate) fn extract_merkle_tree_state_transition_proofs(
|
|||
| middleware::Operation::ContainerDeleteFromEntries(_, _, _, pf) => pf.clone(),
|
||||
_ => continue,
|
||||
};
|
||||
aux_list[i] = OperationAux::MerkleTreeStateTransitionProofIndex(table.len());
|
||||
table.push(pf);
|
||||
if pf.op_proof.existence
|
||||
// TODO: Make sure there's no off-by-one error here
|
||||
&& pf.siblings.len() <= params.containers.max_depth_small
|
||||
&& tables.small.len() < params.containers.transition.max_small
|
||||
{
|
||||
aux_list[i] = OperationAux::MerkleTransitionProofIndex(Size::Small, tables.small.len());
|
||||
tables.small.push(pf);
|
||||
} else {
|
||||
aux_list[i] =
|
||||
OperationAux::MerkleTransitionProofIndex(Size::Medium, tables.medium.len());
|
||||
tables.medium.push(pf);
|
||||
}
|
||||
if table.len() > params.max_merkle_tree_state_transition_proofs_containers {
|
||||
}
|
||||
if tables.medium.len() > params.containers.transition.max_medium {
|
||||
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
|
||||
tables.medium.len(),
|
||||
params.containers.transition.max_medium
|
||||
)));
|
||||
}
|
||||
Ok(table)
|
||||
Ok(tables)
|
||||
}
|
||||
|
||||
pub(crate) fn extract_public_key_of(
|
||||
|
|
@ -513,6 +540,8 @@ impl MainPodProver for Prover {
|
|||
let mut aux_list = vec![OperationAux::None; params.max_priv_statements()];
|
||||
let merkle_proofs =
|
||||
extract_merkle_proofs(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
||||
let merkle_transition_proofs =
|
||||
extract_merkle_transition_proofs(params, &mut aux_list, inputs.operations)?;
|
||||
let custom_predicates = extract_custom_predicates(params, inputs.operations)?;
|
||||
let custom_predicate_verifications = extract_custom_predicate_verifications(
|
||||
params,
|
||||
|
|
@ -537,9 +566,6 @@ impl MainPodProver for Prover {
|
|||
let signed_bys =
|
||||
extract_signatures(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,
|
||||
|
|
@ -572,20 +598,15 @@ impl MainPodProver for Prover {
|
|||
.collect_vec();
|
||||
|
||||
let mut vd_mt_proofs = Vec::with_capacity(inputs.pods.len());
|
||||
let pad_vd_mt_proof = inputs.vd_set.get_vds_proof_0();
|
||||
for (pod, vd) in inputs.pods.iter().zip(&verifier_datas) {
|
||||
vd_mt_proofs.push(if pod.is_main() {
|
||||
(true, inputs.vd_set.get_vds_proof(vd)?)
|
||||
inputs.vd_set.get_vds_proof(vd)?
|
||||
} else {
|
||||
// For intro pods we don't verify inclusion of their vk into the vd set, so we
|
||||
// generate a dummy mt proof with expected root and value to pass some constraints
|
||||
(
|
||||
false,
|
||||
MerkleClaimAndProof {
|
||||
root: inputs.vd_set.root(),
|
||||
value: RawValue::from(pod.verifier_data_hash()),
|
||||
..MerkleClaimAndProof::empty()
|
||||
},
|
||||
)
|
||||
// use a valid vds proof that matches the expected root but not the value to pass
|
||||
// the constraints
|
||||
pad_vd_mt_proof.clone()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -598,7 +619,7 @@ impl MainPodProver for Prover {
|
|||
merkle_proofs,
|
||||
public_key_of_sks,
|
||||
signed_bys,
|
||||
merkle_tree_state_transition_proofs,
|
||||
merkle_transition_proofs,
|
||||
custom_predicates_with_mpt_proofs,
|
||||
custom_predicate_verifications,
|
||||
};
|
||||
|
|
@ -985,7 +1006,18 @@ pub mod tests {
|
|||
max_statements: 2,
|
||||
max_public_statements: 1,
|
||||
max_input_pods_public_statements: 0,
|
||||
max_merkle_proofs_containers: 0,
|
||||
containers: middleware::ParamsContainers {
|
||||
state: middleware::ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 0,
|
||||
},
|
||||
transition: middleware::ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 0,
|
||||
},
|
||||
max_depth_small: 8,
|
||||
max_depth_medium: 32,
|
||||
},
|
||||
max_public_key_of: 0,
|
||||
max_custom_predicate_verifications: 0,
|
||||
max_custom_predicates: 0,
|
||||
|
|
@ -1024,11 +1056,20 @@ pub mod tests {
|
|||
max_custom_predicates: 2,
|
||||
max_custom_predicate_verifications: 2,
|
||||
max_custom_predicate_wildcards: 3,
|
||||
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,
|
||||
containers: middleware::ParamsContainers {
|
||||
state: middleware::ParamsMerkleProofs {
|
||||
max_small: 2,
|
||||
max_medium: 2,
|
||||
},
|
||||
transition: middleware::ParamsMerkleProofs {
|
||||
max_small: 2,
|
||||
max_medium: 2,
|
||||
},
|
||||
max_depth_small: 2,
|
||||
max_depth_medium: 4,
|
||||
},
|
||||
};
|
||||
let mut vds = DEFAULT_VD_LIST.clone();
|
||||
vds.push(rec_main_pod_circuit_data(¶ms).1.verifier_only.clone());
|
||||
|
|
@ -1087,8 +1128,18 @@ pub mod tests {
|
|||
max_public_statements: 4,
|
||||
max_custom_predicate_wildcards: 4,
|
||||
max_custom_predicate_verifications: 2,
|
||||
max_merkle_proofs_containers: 3,
|
||||
max_merkle_tree_state_transition_proofs_containers: 0,
|
||||
containers: middleware::ParamsContainers {
|
||||
state: middleware::ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 3,
|
||||
},
|
||||
transition: middleware::ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 0,
|
||||
},
|
||||
max_depth_small: 8,
|
||||
max_depth_medium: 32,
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
println!("{:#?}", params);
|
||||
|
|
@ -1156,8 +1207,18 @@ pub mod tests {
|
|||
max_public_statements: 2,
|
||||
max_custom_predicate_wildcards: 4,
|
||||
max_custom_predicate_verifications: 2,
|
||||
max_merkle_proofs_containers: 0,
|
||||
max_merkle_tree_state_transition_proofs_containers: 0,
|
||||
containers: middleware::ParamsContainers {
|
||||
state: middleware::ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 0,
|
||||
},
|
||||
transition: middleware::ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 0,
|
||||
},
|
||||
max_depth_small: 8,
|
||||
max_depth_medium: 32,
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let mut vds = DEFAULT_VD_LIST.clone();
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||
use crate::{
|
||||
backends::plonky2::{
|
||||
error::{Error, Result},
|
||||
mainpod::{SignedBy, Statement},
|
||||
primitives::merkletree::{MerkleClaimAndProof, MerkleTreeStateTransitionProof},
|
||||
mainpod::{MerkleProofs, MerkleTransitionProofs, SignedBy, Statement},
|
||||
},
|
||||
middleware::{self, OperationType, Params},
|
||||
};
|
||||
|
|
@ -30,50 +29,89 @@ impl OperationArg {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Size {
|
||||
Small,
|
||||
Medium,
|
||||
}
|
||||
|
||||
impl fmt::Display for Size {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Small => write!(f, "small"),
|
||||
Self::Medium => write!(f, "medium"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Size {
|
||||
pub const fn min() -> Self {
|
||||
Self::Small
|
||||
}
|
||||
pub const fn max() -> Self {
|
||||
Self::Medium
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum OperationAux {
|
||||
None,
|
||||
MerkleProofIndex(usize),
|
||||
MerkleProofIndex(Size, usize),
|
||||
MerkleTransitionProofIndex(Size, usize),
|
||||
PublicKeyOfIndex(usize),
|
||||
SignedByIndex(usize),
|
||||
MerkleTreeStateTransitionProofIndex(usize),
|
||||
CustomPredVerifyIndex(usize),
|
||||
}
|
||||
|
||||
impl OperationAux {
|
||||
fn table_offset_merkle_proof(_params: &Params) -> usize {
|
||||
fn table_offset_merkle_proof(params: &Params, size: Size) -> usize {
|
||||
match size {
|
||||
// At index 0 we store a zero entry
|
||||
1
|
||||
Size::Small => 1,
|
||||
Size::Medium => {
|
||||
Self::table_offset_merkle_proof(params, Size::Small)
|
||||
+ params.containers.state.max_small
|
||||
}
|
||||
}
|
||||
}
|
||||
fn table_offset_merkle_transition_proof(params: &Params, size: Size) -> usize {
|
||||
match size {
|
||||
Size::Small => {
|
||||
Self::table_offset_merkle_proof(params, Size::min())
|
||||
+ params.containers.state.max_total()
|
||||
}
|
||||
Size::Medium => {
|
||||
Self::table_offset_merkle_transition_proof(params, Size::Small)
|
||||
+ params.containers.transition.max_small
|
||||
}
|
||||
}
|
||||
}
|
||||
fn table_offset_custom_pred_verify(params: &Params) -> usize {
|
||||
Self::table_offset_merkle_transition_proof(params, Size::min())
|
||||
+ params.containers.transition.max_total()
|
||||
}
|
||||
fn table_offset_public_key_of(params: &Params) -> usize {
|
||||
Self::table_offset_merkle_proof(params) + params.max_merkle_proofs_containers
|
||||
Self::table_offset_custom_pred_verify(params) + params.max_custom_predicate_verifications
|
||||
}
|
||||
fn table_offset_signed_by(params: &Params) -> usize {
|
||||
Self::table_offset_public_key_of(params) + params.max_public_key_of
|
||||
}
|
||||
fn table_offset_merkle_tree_state_transition_proof(params: &Params) -> usize {
|
||||
Self::table_offset_signed_by(params) + params.max_signed_by
|
||||
}
|
||||
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
|
||||
1 + params.containers.state.max_total()
|
||||
+ params.containers.transition.max_total()
|
||||
+ params.max_custom_predicate_verifications
|
||||
+ params.max_public_key_of
|
||||
+ params.max_signed_by
|
||||
+ params.max_merkle_tree_state_transition_proofs_containers
|
||||
+ params.max_custom_predicate_verifications
|
||||
}
|
||||
pub fn table_index(&self, params: &Params) -> usize {
|
||||
match self {
|
||||
Self::None => 0,
|
||||
Self::MerkleProofIndex(i) => Self::table_offset_merkle_proof(params) + *i,
|
||||
Self::MerkleProofIndex(size, i) => Self::table_offset_merkle_proof(params, *size) + *i,
|
||||
Self::MerkleTransitionProofIndex(size, i) => {
|
||||
Self::table_offset_merkle_transition_proof(params, *size) + *i
|
||||
}
|
||||
Self::PublicKeyOfIndex(i) => Self::table_offset_public_key_of(params) + *i,
|
||||
Self::SignedByIndex(i) => Self::table_offset_signed_by(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,
|
||||
}
|
||||
}
|
||||
|
|
@ -96,8 +134,8 @@ impl Operation {
|
|||
&self,
|
||||
statements: &[Statement],
|
||||
signatures: &[SignedBy],
|
||||
merkle_proofs: &[MerkleClaimAndProof],
|
||||
merkle_tree_state_transition_proofs: &[MerkleTreeStateTransitionProof],
|
||||
merkle_proofs: &MerkleProofs,
|
||||
merkle_transition_proofs: &MerkleTransitionProofs,
|
||||
) -> Result<crate::middleware::Operation> {
|
||||
let deref_args = self
|
||||
.1
|
||||
|
|
@ -113,17 +151,26 @@ impl Operation {
|
|||
.collect::<Result<Vec<_>>>()?;
|
||||
let deref_aux = match self.2 {
|
||||
OperationAux::None => crate::middleware::OperationAux::None,
|
||||
OperationAux::CustomPredVerifyIndex(_) => crate::middleware::OperationAux::None,
|
||||
OperationAux::MerkleProofIndex(i) => crate::middleware::OperationAux::MerkleProof(
|
||||
merkle_proofs
|
||||
OperationAux::MerkleProofIndex(size, i) => {
|
||||
let table = match size {
|
||||
Size::Small => &merkle_proofs.small,
|
||||
Size::Medium => &merkle_proofs.medium,
|
||||
};
|
||||
crate::middleware::OperationAux::MerkleProof(
|
||||
table
|
||||
.get(i)
|
||||
.ok_or(Error::custom(format!("Missing Merkle proof index {}", i)))?
|
||||
.proof
|
||||
.clone(),
|
||||
),
|
||||
OperationAux::MerkleTreeStateTransitionProofIndex(i) => {
|
||||
)
|
||||
}
|
||||
OperationAux::MerkleTransitionProofIndex(size, i) => {
|
||||
let table = match size {
|
||||
Size::Small => &merkle_transition_proofs.small,
|
||||
Size::Medium => &merkle_transition_proofs.medium,
|
||||
};
|
||||
crate::middleware::OperationAux::MerkleTreeStateTransitionProof(
|
||||
merkle_tree_state_transition_proofs
|
||||
table
|
||||
.get(i)
|
||||
.ok_or(Error::custom(format!(
|
||||
"Missing Merkle state transition proof index {}",
|
||||
|
|
@ -132,6 +179,7 @@ impl Operation {
|
|||
.clone(),
|
||||
)
|
||||
}
|
||||
OperationAux::CustomPredVerifyIndex(_) => crate::middleware::OperationAux::None,
|
||||
OperationAux::SignedByIndex(i) => crate::middleware::OperationAux::Signature(
|
||||
signatures
|
||||
.get(i)
|
||||
|
|
@ -165,12 +213,14 @@ impl fmt::Display for Operation {
|
|||
}
|
||||
match self.2 {
|
||||
OperationAux::None => (),
|
||||
OperationAux::MerkleProofIndex(i) => write!(f, " merkle_proof_{:02}", i)?,
|
||||
OperationAux::MerkleProofIndex(size, i) => {
|
||||
write!(f, " {}_merkle_proof_{:02}", size, i)?
|
||||
}
|
||||
OperationAux::CustomPredVerifyIndex(i) => write!(f, " custom_pred_verify_{:02}", i)?,
|
||||
OperationAux::PublicKeyOfIndex(i) => write!(f, " public_key_of_{:02}", i)?,
|
||||
OperationAux::SignedByIndex(i) => write!(f, " signed_by_{:02}", i)?,
|
||||
OperationAux::MerkleTreeStateTransitionProofIndex(i) => {
|
||||
write!(f, " merkle_tree_state_transition_proof_{:02}", i)?
|
||||
OperationAux::MerkleTransitionProofIndex(size, i) => {
|
||||
write!(f, " {}_merkle_transition_proof_{:02}", size, i)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -11,13 +11,12 @@ use crate::{
|
|||
basetypes::{Proof, VerifierOnlyCircuitData},
|
||||
error::{Error, Result},
|
||||
mainpod::{
|
||||
calculate_statements_hash, extract_merkle_proofs,
|
||||
extract_merkle_tree_state_transition_proofs, extract_signatures, layout_statements,
|
||||
process_private_statements_operations, process_public_statements_operations, Operation,
|
||||
calculate_statements_hash, extract_merkle_proofs, extract_merkle_transition_proofs,
|
||||
extract_signatures, layout_statements, process_private_statements_operations,
|
||||
process_public_statements_operations, MerkleProofs, MerkleTransitionProofs, Operation,
|
||||
OperationAux, SignedBy, Statement,
|
||||
},
|
||||
mock::emptypod::MockEmptyPod,
|
||||
primitives::merkletree::{MerkleClaimAndProof, MerkleTreeStateTransitionProof},
|
||||
recursion::hash_verifier_data,
|
||||
},
|
||||
middleware::{
|
||||
|
|
@ -45,10 +44,10 @@ pub struct MockMainPod {
|
|||
operations: Vec<Operation>,
|
||||
// public subset of the `statements` vector
|
||||
public_statements: Vec<Statement>,
|
||||
// All Merkle proofs
|
||||
merkle_proofs_containers: Vec<MerkleClaimAndProof>,
|
||||
// All Merkle tree state transition proofs
|
||||
merkle_tree_state_transition_proofs_containers: Vec<MerkleTreeStateTransitionProof>,
|
||||
// All Merkle proofs for containers
|
||||
merkle_proofs: MerkleProofs,
|
||||
// All Merkle tree state transition proofs for containers
|
||||
merkle_transition_proofs: MerkleTransitionProofs,
|
||||
// All verified signatures
|
||||
signatures: Vec<SignedBy>,
|
||||
}
|
||||
|
|
@ -124,8 +123,8 @@ struct Data {
|
|||
public_statements: Vec<Statement>,
|
||||
operations: Vec<Operation>,
|
||||
statements: Vec<Statement>,
|
||||
merkle_proofs: Vec<MerkleClaimAndProof>,
|
||||
merkle_tree_state_transition_proofs: Vec<MerkleTreeStateTransitionProof>,
|
||||
merkle_proofs: MerkleProofs,
|
||||
merkle_transition_proofs: MerkleTransitionProofs,
|
||||
signatures: Vec<SignedBy>,
|
||||
input_pods: Vec<(usize, Params, Hash, VDSet, serde_json::Value)>,
|
||||
}
|
||||
|
|
@ -153,8 +152,8 @@ impl MockMainPod {
|
|||
let merkle_proofs =
|
||||
extract_merkle_proofs(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
||||
// Similarly for Merkle state transition proofs.
|
||||
let merkle_tree_state_transition_proofs =
|
||||
extract_merkle_tree_state_transition_proofs(params, &mut aux_list, inputs.operations)?;
|
||||
let merkle_transition_proofs =
|
||||
extract_merkle_transition_proofs(params, &mut aux_list, inputs.operations)?;
|
||||
let signatures =
|
||||
extract_signatures(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
||||
|
||||
|
|
@ -185,8 +184,8 @@ impl MockMainPod {
|
|||
public_statements,
|
||||
statements,
|
||||
operations,
|
||||
merkle_proofs_containers: merkle_proofs,
|
||||
merkle_tree_state_transition_proofs_containers: merkle_tree_state_transition_proofs,
|
||||
merkle_proofs,
|
||||
merkle_transition_proofs,
|
||||
signatures,
|
||||
})
|
||||
}
|
||||
|
|
@ -260,8 +259,8 @@ impl Pod for MockMainPod {
|
|||
.deref(
|
||||
&self.statements[..input_statement_offset + i],
|
||||
&self.signatures,
|
||||
&self.merkle_proofs_containers,
|
||||
&self.merkle_tree_state_transition_proofs_containers,
|
||||
&self.merkle_proofs,
|
||||
&self.merkle_transition_proofs,
|
||||
)?
|
||||
.check_and_log(&self.params, &s.clone().try_into()?)
|
||||
.map_err(|e| e.into())
|
||||
|
|
@ -321,10 +320,8 @@ impl Pod for MockMainPod {
|
|||
public_statements: self.public_statements.clone(),
|
||||
operations: self.operations.clone(),
|
||||
statements: self.statements.clone(),
|
||||
merkle_proofs: self.merkle_proofs_containers.clone(),
|
||||
merkle_tree_state_transition_proofs: self
|
||||
.merkle_tree_state_transition_proofs_containers
|
||||
.clone(),
|
||||
merkle_proofs: self.merkle_proofs.clone(),
|
||||
merkle_transition_proofs: self.merkle_transition_proofs.clone(),
|
||||
signatures: self.signatures.clone(),
|
||||
input_pods,
|
||||
})
|
||||
|
|
@ -344,7 +341,7 @@ impl Pod for MockMainPod {
|
|||
operations,
|
||||
statements,
|
||||
merkle_proofs,
|
||||
merkle_tree_state_transition_proofs,
|
||||
merkle_transition_proofs,
|
||||
signatures,
|
||||
input_pods,
|
||||
} = serde_json::from_value(data)?;
|
||||
|
|
@ -362,8 +359,8 @@ impl Pod for MockMainPod {
|
|||
public_statements,
|
||||
operations,
|
||||
statements,
|
||||
merkle_proofs_containers: merkle_proofs,
|
||||
merkle_tree_state_transition_proofs_containers: merkle_tree_state_transition_proofs,
|
||||
merkle_proofs,
|
||||
merkle_transition_proofs,
|
||||
signatures,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,6 @@ use crate::{
|
|||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct MerkleClaimAndProofTarget {
|
||||
pub(crate) max_depth: usize,
|
||||
// `enabled` determines if the merkleproof verification is enabled
|
||||
pub(crate) enabled: BoolTarget,
|
||||
pub(crate) root: HashOutTarget,
|
||||
pub(crate) key: ValueTarget,
|
||||
pub(crate) value: ValueTarget,
|
||||
|
|
@ -121,16 +119,9 @@ pub fn verify_merkle_proof_circuit(
|
|||
let obtained_root =
|
||||
compute_root_from_leaf(max_depth, builder, &path, &leaf_hash, &proof.siblings);
|
||||
|
||||
// check that obtained_root==root (from inputs), when enabled==true
|
||||
let zero = builder.zero();
|
||||
let expected_root: Vec<Target> = (0..HASH_SIZE)
|
||||
.map(|j| builder.select(proof.enabled, proof.root.elements[j], zero))
|
||||
.collect();
|
||||
let computed_root: Vec<Target> = (0..HASH_SIZE)
|
||||
.map(|j| builder.select(proof.enabled, obtained_root.elements[j], zero))
|
||||
.collect();
|
||||
// check that obtained_root==root (from inputs)
|
||||
for j in 0..HASH_SIZE {
|
||||
builder.connect(computed_root[j], expected_root[j]);
|
||||
builder.connect(obtained_root.elements[j], proof.root.elements[j]);
|
||||
}
|
||||
measure_gates_end!(builder, measure);
|
||||
}
|
||||
|
|
@ -139,7 +130,6 @@ impl MerkleClaimAndProofTarget {
|
|||
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
||||
MerkleClaimAndProofTarget {
|
||||
max_depth,
|
||||
enabled: builder.add_virtual_bool_target_safe(),
|
||||
root: builder.add_virtual_hash(),
|
||||
key: builder.add_virtual_value(),
|
||||
value: builder.add_virtual_value(),
|
||||
|
|
@ -154,12 +144,7 @@ impl MerkleClaimAndProofTarget {
|
|||
}
|
||||
/// assigns the given values to the targets
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn set_targets(
|
||||
&self,
|
||||
pw: &mut PartialWitness<F>,
|
||||
enabled: bool,
|
||||
mp: &MerkleClaimAndProof,
|
||||
) -> Result<()> {
|
||||
pub fn set_targets(&self, pw: &mut PartialWitness<F>, mp: &MerkleClaimAndProof) -> Result<()> {
|
||||
if mp.proof.siblings.len() > self.max_depth {
|
||||
return Err(Error::Tree(TreeError::circuit_depth_too_small(
|
||||
self.max_depth,
|
||||
|
|
@ -167,7 +152,6 @@ impl MerkleClaimAndProofTarget {
|
|||
)));
|
||||
}
|
||||
|
||||
pw.set_bool_target(self.enabled, enabled)?;
|
||||
pw.set_hash_target(self.root, HashOut::from_vec(mp.root.0.to_vec()))?;
|
||||
pw.set_target_arr(&self.key.elements, &mp.key.0)?;
|
||||
pw.set_target_arr(&self.value.elements, &mp.value.0)?;
|
||||
|
|
@ -207,8 +191,6 @@ impl MerkleClaimAndProofTarget {
|
|||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct MerkleProofExistenceTarget {
|
||||
max_depth: usize,
|
||||
// `enabled` determines if the merkleproof verification is enabled
|
||||
pub(crate) enabled: BoolTarget,
|
||||
pub(crate) root: HashOutTarget,
|
||||
pub(crate) key: ValueTarget,
|
||||
pub(crate) value: ValueTarget,
|
||||
|
|
@ -236,16 +218,9 @@ pub fn verify_merkle_proof_existence_circuit(
|
|||
let obtained_root =
|
||||
compute_root_from_leaf(max_depth, builder, &path, &leaf_hash, &proof.siblings);
|
||||
|
||||
// check that obtained_root==root (from inputs), when enabled==true
|
||||
let zero = builder.zero();
|
||||
let expected_root: Vec<Target> = (0..HASH_SIZE)
|
||||
.map(|j| builder.select(proof.enabled, proof.root.elements[j], zero))
|
||||
.collect();
|
||||
let computed_root: Vec<Target> = (0..HASH_SIZE)
|
||||
.map(|j| builder.select(proof.enabled, obtained_root.elements[j], zero))
|
||||
.collect();
|
||||
// check that obtained_root==root (from inputs)
|
||||
for j in 0..HASH_SIZE {
|
||||
builder.connect(computed_root[j], expected_root[j]);
|
||||
builder.connect(obtained_root.elements[j], proof.root.elements[j]);
|
||||
}
|
||||
measure_gates_end!(builder, measure);
|
||||
|
||||
|
|
@ -256,7 +231,6 @@ impl MerkleProofExistenceTarget {
|
|||
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
||||
MerkleProofExistenceTarget {
|
||||
max_depth,
|
||||
enabled: builder.add_virtual_bool_target_safe(),
|
||||
root: builder.add_virtual_hash(),
|
||||
key: builder.add_virtual_value(),
|
||||
value: builder.add_virtual_value(),
|
||||
|
|
@ -265,12 +239,7 @@ impl MerkleProofExistenceTarget {
|
|||
}
|
||||
}
|
||||
/// assigns the given values to the targets
|
||||
pub fn set_targets(
|
||||
&self,
|
||||
pw: &mut PartialWitness<F>,
|
||||
enabled: bool,
|
||||
mp: &MerkleClaimAndProof,
|
||||
) -> Result<()> {
|
||||
pub fn set_targets(&self, pw: &mut PartialWitness<F>, mp: &MerkleClaimAndProof) -> Result<()> {
|
||||
assert!(mp.proof.existence); // sanity check
|
||||
if mp.proof.siblings.len() > self.max_depth {
|
||||
return Err(Error::Tree(TreeError::circuit_depth_too_small(
|
||||
|
|
@ -279,7 +248,6 @@ impl MerkleProofExistenceTarget {
|
|||
)));
|
||||
}
|
||||
|
||||
pw.set_bool_target(self.enabled, enabled)?;
|
||||
pw.set_hash_target(self.root, HashOut::from_vec(mp.root.0.to_vec()))?;
|
||||
pw.set_target_arr(&self.key.elements, &mp.key.0)?;
|
||||
pw.set_target_arr(&self.value.elements, &mp.value.0)?;
|
||||
|
|
@ -456,8 +424,6 @@ fn hash_with_flag_target<H: AlgebraicHasher<F>>(
|
|||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct MerkleTreeStateTransitionProofTarget {
|
||||
pub(crate) max_depth: usize,
|
||||
// `enabled` determines if the merkleproof state transition verification is enabled
|
||||
pub(crate) enabled: BoolTarget,
|
||||
pub(crate) op: Target,
|
||||
pub(crate) old_root: HashOutTarget,
|
||||
pub(crate) op_proof: MerkleClaimAndProofTarget,
|
||||
|
|
@ -511,7 +477,6 @@ pub fn verify_merkle_state_transition_circuit(
|
|||
};
|
||||
let new_key_proof = MerkleProofExistenceTarget {
|
||||
max_depth: proof.max_depth,
|
||||
enabled: proof.enabled,
|
||||
root,
|
||||
key: proof.op_key,
|
||||
value: proof.op_value,
|
||||
|
|
@ -523,13 +488,7 @@ pub fn verify_merkle_state_transition_circuit(
|
|||
// Insert/Delete: Non-existence
|
||||
// Update: Existence
|
||||
let proof_type = is_update;
|
||||
builder.conditional_assert_eq(
|
||||
proof.enabled.target,
|
||||
proof.op_proof.existence.target,
|
||||
proof_type.target,
|
||||
);
|
||||
// 3.2) assert that proof.enabled matches with op_proof.enabled
|
||||
builder.connect(proof.op_proof.enabled.target, proof.enabled.target);
|
||||
builder.connect(proof.op_proof.existence.target, proof_type.target);
|
||||
|
||||
// 4) assert proof_non_existence.root corresponds to the root
|
||||
// specified by the op (old_root for Insert/Update and new_root
|
||||
|
|
@ -545,17 +504,9 @@ pub fn verify_merkle_state_transition_circuit(
|
|||
};
|
||||
for j in 0..HASH_SIZE {
|
||||
// 4.1) assert that proof.proof_non_existence.root == proof.old_root
|
||||
builder.conditional_assert_eq(
|
||||
proof.enabled.target,
|
||||
proof.op_proof.root.elements[j],
|
||||
claim_root.elements[j],
|
||||
);
|
||||
builder.connect(proof.op_proof.root.elements[j], claim_root.elements[j]);
|
||||
// 4.2) assert that the non-existence proof uses the op_key (value not needed).
|
||||
builder.conditional_assert_eq(
|
||||
proof.enabled.target,
|
||||
proof.op_proof.key.elements[j],
|
||||
proof.op_key.elements[j],
|
||||
);
|
||||
builder.connect(proof.op_proof.key.elements[j], proof.op_key.elements[j]);
|
||||
}
|
||||
|
||||
// prepare value for check 5.2)
|
||||
|
|
@ -593,7 +544,7 @@ pub fn verify_merkle_state_transition_circuit(
|
|||
.map(|j| builder.select(is_divergence_level, zero, new_siblings[i].elements[j]))
|
||||
.collect();
|
||||
for j in 0..HASH_SIZE {
|
||||
builder.conditional_assert_eq(proof.enabled.target, old_sibling_i[j], new_sibling_i[j]);
|
||||
builder.connect(old_sibling_i[j], new_sibling_i[j]);
|
||||
}
|
||||
|
||||
// 5.2) when i==d && if old_siblings[i] != new_siblings[i], check that:
|
||||
|
|
@ -611,7 +562,7 @@ pub fn verify_merkle_state_transition_circuit(
|
|||
let in_case_5_2 = builder.and(old_is_noteq_new, is_divergence_level);
|
||||
|
||||
// do the case2's checks
|
||||
let sel = builder.and(proof.enabled, in_case_5_2);
|
||||
let sel = in_case_5_2;
|
||||
for j in 0..HASH_SIZE {
|
||||
builder.conditional_assert_eq(sel.target, old_siblings[i].elements[j], zero);
|
||||
builder.conditional_assert_eq(
|
||||
|
|
@ -641,7 +592,6 @@ impl MerkleTreeStateTransitionProofTarget {
|
|||
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
||||
Self {
|
||||
max_depth,
|
||||
enabled: builder.add_virtual_bool_target_safe(),
|
||||
op: builder.add_virtual_target(),
|
||||
|
||||
old_root: builder.add_virtual_hash(),
|
||||
|
|
@ -661,7 +611,6 @@ impl MerkleTreeStateTransitionProofTarget {
|
|||
pub fn set_targets(
|
||||
&self,
|
||||
pw: &mut PartialWitness<F>,
|
||||
enabled: bool,
|
||||
mp: &MerkleTreeStateTransitionProof,
|
||||
) -> Result<()> {
|
||||
let new_siblings = mp.siblings.clone();
|
||||
|
|
@ -672,13 +621,11 @@ impl MerkleTreeStateTransitionProofTarget {
|
|||
)));
|
||||
}
|
||||
|
||||
pw.set_bool_target(self.enabled, enabled)?;
|
||||
pw.set_target(self.op, F::from_canonical_u8(mp.op as u8))?;
|
||||
|
||||
pw.set_hash_target(self.old_root, HashOut::from_vec(mp.old_root.0.to_vec()))?;
|
||||
self.op_proof.set_targets(
|
||||
pw,
|
||||
enabled,
|
||||
&MerkleClaimAndProof {
|
||||
root: if mp.op == MerkleTreeOp::Delete {
|
||||
mp.new_root
|
||||
|
|
@ -859,7 +806,6 @@ pub mod tests {
|
|||
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||
targets.set_targets(
|
||||
&mut pw,
|
||||
true,
|
||||
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
||||
)?;
|
||||
|
||||
|
|
@ -871,6 +817,42 @@ pub mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merkleproof_pad_valid() -> Result<()> {
|
||||
// circuit
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
|
||||
let targets = MerkleClaimAndProofTarget::new_virtual(32, &mut builder);
|
||||
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||
targets.set_targets(&mut pw, &MerkleClaimAndProof::pad())?;
|
||||
|
||||
// generate & verify proof
|
||||
let data = builder.build::<C>();
|
||||
let proof = data.prove(pw)?;
|
||||
data.verify(proof)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merkleproof_transition_pad_valid() -> Result<()> {
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
|
||||
let targets = MerkleTreeStateTransitionProofTarget::new_virtual(32, &mut builder);
|
||||
verify_merkle_state_transition_circuit(&mut builder, &targets);
|
||||
targets.set_targets(&mut pw, &MerkleTreeStateTransitionProof::pad())?;
|
||||
|
||||
// generate & verify proof
|
||||
let data = builder.build::<C>();
|
||||
let proof = data.prove(pw)?;
|
||||
data.verify(proof)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merkleproof_only_existence_verify() -> Result<()> {
|
||||
for max_depth in [10, 16, 32, 40, 64, 128, 130, 250, 256] {
|
||||
|
|
@ -906,7 +888,6 @@ pub mod tests {
|
|||
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||
targets.set_targets(
|
||||
&mut pw,
|
||||
true,
|
||||
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
||||
)?;
|
||||
|
||||
|
|
@ -982,7 +963,6 @@ pub mod tests {
|
|||
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||
targets.set_targets(
|
||||
&mut pw,
|
||||
true,
|
||||
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
||||
)?;
|
||||
|
||||
|
|
@ -1028,32 +1008,15 @@ pub mod tests {
|
|||
|
||||
let targets = MerkleClaimAndProofTarget::new_virtual(max_depth, &mut builder);
|
||||
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||
// verification enabled & proof of existence
|
||||
// proof of existence
|
||||
let mp = MerkleClaimAndProof::new(tree2.root(), key, Some(value), proof);
|
||||
targets.set_targets(&mut pw, true, &mp)?;
|
||||
targets.set_targets(&mut pw, &mp)?;
|
||||
|
||||
// generate proof, expecting it to fail (since we're using the wrong
|
||||
// root)
|
||||
let data = builder.build::<C>();
|
||||
assert!(data.prove(pw).is_err());
|
||||
|
||||
// Now generate a new proof, using `enabled=false`, which should pass the verification
|
||||
// despite containing 'wrong' witness.
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
|
||||
let targets = MerkleClaimAndProofTarget::new_virtual(max_depth, &mut builder);
|
||||
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||
// verification disabled & proof of existence
|
||||
targets.set_targets(&mut pw, false, &mp)?;
|
||||
|
||||
// generate proof, should pass despite using wrong witness, since the
|
||||
// `enabled=false`
|
||||
let data = builder.build::<C>();
|
||||
let proof = data.prove(pw)?;
|
||||
data.verify(proof)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1076,7 +1039,7 @@ pub mod tests {
|
|||
|
||||
let targets = MerkleTreeStateTransitionProofTarget::new_virtual(max_depth, &mut builder);
|
||||
verify_merkle_state_transition_circuit(&mut builder, &targets);
|
||||
targets.set_targets(&mut pw, true, state_transition_proof)?;
|
||||
targets.set_targets(&mut pw, state_transition_proof)?;
|
||||
|
||||
// generate & verify proof
|
||||
let data = builder.build::<C>();
|
||||
|
|
@ -1273,71 +1236,4 @@ pub mod tests {
|
|||
assert_ne!(state_transition_proof.new_root, tree.root()); // Tamper check
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_transition_gadget_disabled() -> Result<()> {
|
||||
let max_depth: usize = 32;
|
||||
let mut kvs = HashMap::new();
|
||||
for i in 0..8 {
|
||||
kvs.insert(RawValue::from(i), RawValue::from(1000 + i));
|
||||
}
|
||||
let mut tree = MerkleTree::new(&kvs);
|
||||
|
||||
let key = RawValue::from(37);
|
||||
let value = RawValue::from(1037);
|
||||
let _ = tree.insert(&key, &value)?;
|
||||
|
||||
let key = RawValue::from(21);
|
||||
let value = RawValue::from(1021);
|
||||
let original_state_transition_proof = tree.insert(&key, &value)?;
|
||||
|
||||
let mut state_transition_proof = original_state_transition_proof.clone();
|
||||
|
||||
// modify the proof, so that it should fail when `enabled=true`, by
|
||||
// changing the new_root
|
||||
state_transition_proof.new_root = state_transition_proof.old_root;
|
||||
|
||||
run_circuit_disabled(max_depth, &state_transition_proof)?;
|
||||
|
||||
// modify the proof, so that it should fail when `enabled=true`, by
|
||||
// changing the new_sibling at the divergence level, which should not
|
||||
// pass the verification in the case where we're inserting key=21
|
||||
let mut state_transition_proof = original_state_transition_proof.clone();
|
||||
state_transition_proof.siblings[4] = EMPTY_HASH;
|
||||
|
||||
run_circuit_disabled(max_depth, &state_transition_proof)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_circuit_disabled(
|
||||
max_depth: usize,
|
||||
state_transition_proof: &MerkleTreeStateTransitionProof,
|
||||
) -> Result<()> {
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
|
||||
let targets = MerkleTreeStateTransitionProofTarget::new_virtual(max_depth, &mut builder);
|
||||
verify_merkle_state_transition_circuit(&mut builder, &targets);
|
||||
targets.set_targets(&mut pw, true, state_transition_proof)?;
|
||||
|
||||
// generate proof, and expect it to fail
|
||||
let data = builder.build::<C>();
|
||||
assert!(data.prove(pw).is_err()); // expect prove to fail
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
let mut pw = PartialWitness::<F>::new();
|
||||
|
||||
let targets = MerkleTreeStateTransitionProofTarget::new_virtual(max_depth, &mut builder);
|
||||
verify_merkle_state_transition_circuit(&mut builder, &targets);
|
||||
targets.set_targets(&mut pw, false, state_transition_proof)?;
|
||||
|
||||
// generate and expect it to pass
|
||||
let data = builder.build::<C>();
|
||||
let proof = data.prove(pw)?;
|
||||
data.verify(proof)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -921,6 +921,21 @@ impl MerkleClaimAndProof {
|
|||
},
|
||||
}
|
||||
}
|
||||
/// Value used for padding. This is a valid merkle proof.
|
||||
pub fn pad() -> Self {
|
||||
let [key, value] = [EMPTY_VALUE, EMPTY_VALUE];
|
||||
let root = kv_hash(&key, Some(value));
|
||||
Self {
|
||||
root,
|
||||
key,
|
||||
value,
|
||||
proof: MerkleProof {
|
||||
existence: true,
|
||||
siblings: vec![],
|
||||
other_leaf: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn new(root: Hash, key: RawValue, value: Option<RawValue>, proof: MerkleProof) -> Self {
|
||||
Self {
|
||||
root,
|
||||
|
|
@ -974,7 +989,6 @@ pub struct MerkleTreeStateTransitionProof {
|
|||
}
|
||||
|
||||
impl MerkleTreeStateTransitionProof {
|
||||
/// Value used for padding.
|
||||
pub fn empty() -> Self {
|
||||
let empty_proof_and_claim = MerkleClaimAndProof::empty();
|
||||
Self {
|
||||
|
|
@ -988,6 +1002,20 @@ impl MerkleTreeStateTransitionProof {
|
|||
siblings: vec![],
|
||||
}
|
||||
}
|
||||
/// Value used for padding. This is a valid transition proof.
|
||||
pub fn pad() -> Self {
|
||||
let pad_proof_and_claim = MerkleClaimAndProof::pad();
|
||||
Self {
|
||||
op: MerkleTreeOp::Update,
|
||||
old_root: pad_proof_and_claim.root,
|
||||
op_proof: pad_proof_and_claim.proof,
|
||||
new_root: pad_proof_and_claim.root,
|
||||
op_key: pad_proof_and_claim.key,
|
||||
op_value: pad_proof_and_claim.value,
|
||||
value: Some(pad_proof_and_claim.value),
|
||||
siblings: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: currently we use automatic serialization/deserialization, which is
|
||||
|
|
@ -1165,6 +1193,15 @@ pub mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merkletree_pad() {
|
||||
let claim = MerkleClaimAndProof::pad();
|
||||
MerkleTree::verify(claim.root, &claim.proof, &claim.key, &claim.value).unwrap();
|
||||
|
||||
let proof = MerkleTreeStateTransitionProof::pad();
|
||||
MerkleTree::verify_state_transition(&proof).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_key_not_found() -> Result<()> {
|
||||
let db = Box::new(db::MemDB::new());
|
||||
|
|
|
|||
|
|
@ -78,12 +78,12 @@ fn aggregate_rows<'a>(
|
|||
UtilizationRow {
|
||||
name: "merkle proofs",
|
||||
used: merkle_proofs,
|
||||
limit: params.max_merkle_proofs_containers,
|
||||
limit: params.containers.state.max_medium,
|
||||
},
|
||||
UtilizationRow {
|
||||
name: "merkle state transitions",
|
||||
used: merkle_state_transitions,
|
||||
limit: params.max_merkle_tree_state_transition_proofs_containers,
|
||||
limit: params.containers.transition.max_medium,
|
||||
},
|
||||
UtilizationRow {
|
||||
name: "custom pred verifications",
|
||||
|
|
@ -278,15 +278,24 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::{
|
||||
frontend::multi_pod::cost::CustomPredicateId,
|
||||
middleware::{Hash, RawValue},
|
||||
middleware::{Hash, ParamsContainers, ParamsMerkleProofs, RawValue},
|
||||
};
|
||||
|
||||
fn default_params() -> Params {
|
||||
Params {
|
||||
max_statements: 48,
|
||||
max_public_statements: 8,
|
||||
max_merkle_proofs_containers: 8,
|
||||
max_merkle_tree_state_transition_proofs_containers: 4,
|
||||
containers: ParamsContainers {
|
||||
state: ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 8,
|
||||
},
|
||||
transition: ParamsMerkleProofs {
|
||||
max_small: 0,
|
||||
max_medium: 4,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
max_custom_predicate_verifications: 10,
|
||||
max_custom_predicates: 2,
|
||||
max_signed_by: 4,
|
||||
|
|
|
|||
|
|
@ -395,13 +395,11 @@ pub fn solve(input: &SolverInput) -> Result<MultiPodSolution> {
|
|||
let lb_statement_groups = lower_bound_from_total(input.num_statements, max_stmts_per_pod);
|
||||
let lb_merkle = lower_bound_from_total(
|
||||
resource_totals.merkle_proofs,
|
||||
input.params.max_merkle_proofs_containers,
|
||||
input.params.containers.state.max_medium,
|
||||
);
|
||||
let lb_merkle_transitions = lower_bound_from_total(
|
||||
resource_totals.merkle_state_transitions,
|
||||
input
|
||||
.params
|
||||
.max_merkle_tree_state_transition_proofs_containers,
|
||||
input.params.containers.transition.max_medium,
|
||||
);
|
||||
let lb_custom_pred_verifications = lower_bound_from_total(
|
||||
resource_totals.custom_pred_verifications,
|
||||
|
|
@ -753,7 +751,7 @@ fn try_solve_with_pods(
|
|||
.map(|s| (input.costs[s].merkle_proofs as f64) * prove[s][p])
|
||||
.sum();
|
||||
model.add_constraint(constraint!(
|
||||
merkle_sum <= (input.params.max_merkle_proofs_containers as f64) * pod_used[p]
|
||||
merkle_sum <= (input.params.containers.state.max_medium as f64) * pod_used[p]
|
||||
));
|
||||
|
||||
// 6d: Merkle state transitions
|
||||
|
|
@ -761,11 +759,7 @@ fn try_solve_with_pods(
|
|||
.map(|s| (input.costs[s].merkle_state_transitions as f64) * prove[s][p])
|
||||
.sum();
|
||||
model.add_constraint(constraint!(
|
||||
mst_sum
|
||||
<= (input
|
||||
.params
|
||||
.max_merkle_tree_state_transition_proofs_containers as f64)
|
||||
* pod_used[p]
|
||||
mst_sum <= (input.params.containers.transition.max_medium as f64) * pod_used[p]
|
||||
));
|
||||
|
||||
// 6e: Custom predicate verifications
|
||||
|
|
|
|||
|
|
@ -780,6 +780,50 @@ pub const BASE_PARAMS: BaseParams = BaseParams {
|
|||
max_operation_args: 5 + 1,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParamsMerkleProofs {
|
||||
pub max_small: usize,
|
||||
pub max_medium: usize,
|
||||
}
|
||||
|
||||
impl ParamsMerkleProofs {
|
||||
pub fn max_total(&self) -> usize {
|
||||
self.max_small + self.max_medium
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParamsContainers {
|
||||
// Parameters for exists/nonexists container operations. The small set only supports exists
|
||||
pub state: ParamsMerkleProofs,
|
||||
// Parameters for transition container operations (insert, delete, update). The small set only
|
||||
// supports update.
|
||||
pub transition: ParamsMerkleProofs,
|
||||
// Max depth of small proofs
|
||||
pub max_depth_small: usize,
|
||||
// Max depth of medium proofs
|
||||
pub max_depth_medium: usize,
|
||||
}
|
||||
|
||||
impl Default for ParamsContainers {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
state: ParamsMerkleProofs {
|
||||
max_small: 22,
|
||||
max_medium: 8,
|
||||
},
|
||||
transition: ParamsMerkleProofs {
|
||||
max_small: 12,
|
||||
max_medium: 6,
|
||||
},
|
||||
max_depth_small: 8,
|
||||
max_depth_medium: 32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Params: non dynamic parameters that define the circuit.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
@ -793,12 +837,7 @@ pub struct Params {
|
|||
// max number of operations using custom predicates that can be verified in the MainPod
|
||||
pub max_custom_predicate_verifications: usize,
|
||||
pub max_custom_predicate_wildcards: usize,
|
||||
// maximum number of merkle proofs used for container operations
|
||||
pub max_merkle_proofs_containers: usize,
|
||||
// maximum number of merkle tree state transition proofs used for container update operations
|
||||
pub max_merkle_tree_state_transition_proofs_containers: usize,
|
||||
// maximum depth for merkle tree gadget used for container operations
|
||||
pub max_depth_mt_containers: usize,
|
||||
pub containers: ParamsContainers,
|
||||
// maximum depth of the merkle tree gadget used for verifier_data membership
|
||||
// check. This allows creating verifying sets of pod circuits of size
|
||||
// 2^max_depth_mt_vds. Limits the number of container operations of the type Contains,
|
||||
|
|
@ -820,9 +859,7 @@ impl Default for Params {
|
|||
max_custom_predicates: 8,
|
||||
max_custom_predicate_verifications: 8,
|
||||
max_custom_predicate_wildcards: 8,
|
||||
max_merkle_proofs_containers: 20,
|
||||
max_merkle_tree_state_transition_proofs_containers: 6,
|
||||
max_depth_mt_containers: 32,
|
||||
containers: ParamsContainers::default(),
|
||||
max_depth_mt_vds: 6, // up to 64 (2^6) different pod circuits
|
||||
max_public_key_of: 2,
|
||||
max_signed_by: 4,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue