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,
|
mainpod::cache_get_rec_main_pod_verifier_circuit_data,
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
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(|| {
|
pub static DEFAULT_VD_LIST: LazyLock<Vec<VerifierOnlyCircuitData>> = LazyLock::new(|| {
|
||||||
|
|
@ -95,6 +95,12 @@ impl Eq for VDSet {}
|
||||||
|
|
||||||
impl VDSet {
|
impl VDSet {
|
||||||
fn new_from_vds_hashes(mut vds_hashes: Vec<Hash>) -> Self {
|
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
|
// before using the hash values, sort them, so that each set of
|
||||||
// verifier_datas gets the same VDSet root
|
// verifier_datas gets the same VDSet root
|
||||||
vds_hashes.sort();
|
vds_hashes.sort();
|
||||||
|
|
@ -150,6 +156,9 @@ impl VDSet {
|
||||||
))?
|
))?
|
||||||
.clone())
|
.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
|
/// Returns true if the `verifier_data_hash` is in the set
|
||||||
pub fn contains(&self, verifier_data_hash: HashOut) -> bool {
|
pub fn contains(&self, verifier_data_hash: HashOut) -> bool {
|
||||||
self.proofs_map
|
self.proofs_map
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ use crate::{
|
||||||
mainpod::{Operation, OperationArg, OperationAux, Statement},
|
mainpod::{Operation, OperationArg, OperationAux, Statement},
|
||||||
primitives::merkletree::{
|
primitives::merkletree::{
|
||||||
verify_merkle_proof_circuit, MerkleClaimAndProof, MerkleClaimAndProofTarget,
|
verify_merkle_proof_circuit, MerkleClaimAndProof, MerkleClaimAndProofTarget,
|
||||||
MerkleProof, MerkleTreeStateTransitionProofTarget,
|
MerkleProof, MerkleProofExistenceTarget, MerkleTreeStateTransitionProofTarget,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
|
|
@ -725,7 +725,6 @@ impl CustomPredicateInBatchTarget {
|
||||||
let mtp =
|
let mtp =
|
||||||
MerkleClaimAndProofTarget::new_virtual(Params::max_depth_custom_batch_mt(), builder);
|
MerkleClaimAndProofTarget::new_virtual(Params::max_depth_custom_batch_mt(), builder);
|
||||||
let _true = builder._true();
|
let _true = builder._true();
|
||||||
builder.connect(_true.target, mtp.enabled.target);
|
|
||||||
builder.connect(_true.target, mtp.existence.target);
|
builder.connect(_true.target, mtp.existence.target);
|
||||||
let zero = builder.constant(F(0));
|
let zero = builder.constant(F(0));
|
||||||
let key = ValueTarget {
|
let key = ValueTarget {
|
||||||
|
|
@ -763,7 +762,7 @@ impl CustomPredicateInBatchTarget {
|
||||||
value: RawValue::from(hash_fields(&predicate.to_fields())),
|
value: RawValue::from(hash_fields(&predicate.to_fields())),
|
||||||
proof: mtp.clone(),
|
proof: mtp.clone(),
|
||||||
};
|
};
|
||||||
self.mtp.set_targets(pw, true, &mtp_claim)?;
|
self.mtp.set_targets(pw, &mtp_claim)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -987,7 +986,6 @@ pub trait Flattenable {
|
||||||
/// elsewhere.
|
/// elsewhere.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct MerkleClaimTarget {
|
pub struct MerkleClaimTarget {
|
||||||
pub(crate) enabled: BoolTarget,
|
|
||||||
pub(crate) root: HashOutTarget,
|
pub(crate) root: HashOutTarget,
|
||||||
pub(crate) key: ValueTarget,
|
pub(crate) key: ValueTarget,
|
||||||
pub(crate) value: ValueTarget,
|
pub(crate) value: ValueTarget,
|
||||||
|
|
@ -997,7 +995,6 @@ pub struct MerkleClaimTarget {
|
||||||
impl From<MerkleClaimAndProofTarget> for MerkleClaimTarget {
|
impl From<MerkleClaimAndProofTarget> for MerkleClaimTarget {
|
||||||
fn from(pf: MerkleClaimAndProofTarget) -> Self {
|
fn from(pf: MerkleClaimAndProofTarget) -> Self {
|
||||||
Self {
|
Self {
|
||||||
enabled: pf.enabled,
|
|
||||||
root: pf.root,
|
root: pf.root,
|
||||||
key: pf.key,
|
key: pf.key,
|
||||||
value: pf.value,
|
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
|
/// For the purpose of op verification, we need only look up the
|
||||||
/// Merkle state transition claim rather than the Merkle state
|
/// Merkle state transition claim rather than the Merkle state
|
||||||
/// transition proof since it is verified elsewhere.
|
/// transition proof since it is verified elsewhere.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct MerkleTreeStateTransitionClaimTarget {
|
pub struct MerkleTreeStateTransitionClaimTarget {
|
||||||
pub(crate) enabled: BoolTarget,
|
|
||||||
pub(crate) op: Target,
|
pub(crate) op: Target,
|
||||||
pub(crate) old_root: HashOutTarget,
|
pub(crate) old_root: HashOutTarget,
|
||||||
pub(crate) new_root: HashOutTarget,
|
pub(crate) new_root: HashOutTarget,
|
||||||
|
|
@ -1022,7 +1032,6 @@ pub struct MerkleTreeStateTransitionClaimTarget {
|
||||||
impl From<MerkleTreeStateTransitionProofTarget> for MerkleTreeStateTransitionClaimTarget {
|
impl From<MerkleTreeStateTransitionProofTarget> for MerkleTreeStateTransitionClaimTarget {
|
||||||
fn from(pf: MerkleTreeStateTransitionProofTarget) -> Self {
|
fn from(pf: MerkleTreeStateTransitionProofTarget) -> Self {
|
||||||
Self {
|
Self {
|
||||||
enabled: pf.enabled,
|
|
||||||
op: pf.op,
|
op: pf.op,
|
||||||
old_root: pf.old_root,
|
old_root: pf.old_root,
|
||||||
new_root: pf.new_root,
|
new_root: pf.new_root,
|
||||||
|
|
@ -1063,7 +1072,6 @@ impl Flattenable for ValueTarget {
|
||||||
impl Flattenable for MerkleClaimTarget {
|
impl Flattenable for MerkleClaimTarget {
|
||||||
fn flatten(&self) -> Vec<Target> {
|
fn flatten(&self) -> Vec<Target> {
|
||||||
[
|
[
|
||||||
vec![self.enabled.target],
|
|
||||||
self.root.elements.to_vec(),
|
self.root.elements.to_vec(),
|
||||||
self.key.elements.to_vec(),
|
self.key.elements.to_vec(),
|
||||||
self.value.elements.to_vec(),
|
self.value.elements.to_vec(),
|
||||||
|
|
@ -1075,31 +1083,28 @@ impl Flattenable for MerkleClaimTarget {
|
||||||
fn from_flattened(params: &Params, vs: &[Target]) -> Self {
|
fn from_flattened(params: &Params, vs: &[Target]) -> Self {
|
||||||
assert_eq!(vs.len(), Self::size(params));
|
assert_eq!(vs.len(), Self::size(params));
|
||||||
Self {
|
Self {
|
||||||
enabled: BoolTarget::new_unsafe(vs[0]),
|
root: HashOutTarget::from_vec(vs[0..NUM_HASH_OUT_ELTS].to_vec()),
|
||||||
root: HashOutTarget::from_vec(vs[1..1 + NUM_HASH_OUT_ELTS].to_vec()),
|
key: ValueTarget::from_slice(&vs[NUM_HASH_OUT_ELTS..NUM_HASH_OUT_ELTS + VALUE_SIZE]),
|
||||||
key: ValueTarget::from_slice(
|
|
||||||
&vs[1 + NUM_HASH_OUT_ELTS..1 + NUM_HASH_OUT_ELTS + VALUE_SIZE],
|
|
||||||
),
|
|
||||||
value: ValueTarget::from_slice(
|
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 {
|
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 {
|
impl Flattenable for MerkleTreeStateTransitionClaimTarget {
|
||||||
fn flatten(&self) -> Vec<Target> {
|
fn flatten(&self) -> Vec<Target> {
|
||||||
[
|
[
|
||||||
vec![self.enabled.target, self.op],
|
|
||||||
self.old_root.elements.to_vec(),
|
self.old_root.elements.to_vec(),
|
||||||
self.new_root.elements.to_vec(),
|
self.new_root.elements.to_vec(),
|
||||||
self.op_key.elements.to_vec(),
|
self.op_key.elements.to_vec(),
|
||||||
self.op_value.elements.to_vec(),
|
self.op_value.elements.to_vec(),
|
||||||
|
vec![self.op],
|
||||||
]
|
]
|
||||||
.concat()
|
.concat()
|
||||||
}
|
}
|
||||||
|
|
@ -1107,24 +1112,22 @@ impl Flattenable for MerkleTreeStateTransitionClaimTarget {
|
||||||
fn from_flattened(params: &Params, vs: &[Target]) -> Self {
|
fn from_flattened(params: &Params, vs: &[Target]) -> Self {
|
||||||
assert_eq!(vs.len(), Self::size(params));
|
assert_eq!(vs.len(), Self::size(params));
|
||||||
Self {
|
Self {
|
||||||
enabled: BoolTarget::new_unsafe(vs[0]),
|
old_root: HashOutTarget::from_vec(vs[0..NUM_HASH_OUT_ELTS].to_vec()),
|
||||||
op: vs[1],
|
|
||||||
old_root: HashOutTarget::from_vec(vs[2..2 + NUM_HASH_OUT_ELTS].to_vec()),
|
|
||||||
new_root: HashOutTarget::from_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(
|
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(
|
op_value: ValueTarget::from_slice(
|
||||||
&vs[2 * (1 + NUM_HASH_OUT_ELTS) + VALUE_SIZE
|
&vs[2 * NUM_HASH_OUT_ELTS + VALUE_SIZE..2 * NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE],
|
||||||
..2 * (1 + NUM_HASH_OUT_ELTS) + 2 * VALUE_SIZE],
|
|
||||||
),
|
),
|
||||||
|
op: vs[2 * NUM_HASH_OUT_ELTS + 2 * VALUE_SIZE],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(params: &Params) -> usize {
|
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)
|
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.
|
/// Extracts Merkle proofs from Contains/NotContains ops.
|
||||||
pub(crate) fn extract_merkle_proofs(
|
pub(crate) fn extract_merkle_proofs(
|
||||||
params: &Params,
|
params: &Params,
|
||||||
aux_list: &mut [OperationAux],
|
aux_list: &mut [OperationAux],
|
||||||
operations: &[middleware::Operation],
|
operations: &[middleware::Operation],
|
||||||
statements: &[middleware::Statement],
|
statements: &[middleware::Statement],
|
||||||
) -> Result<Vec<MerkleClaimAndProof>> {
|
) -> Result<MerkleProofs> {
|
||||||
let mut table = Vec::new();
|
let mut tables = MerkleProofs::default();
|
||||||
for (i, (op, st)) in operations.iter().zip(statements.iter()).enumerate() {
|
for (i, (op, st)) in operations.iter().zip(statements.iter()).enumerate() {
|
||||||
let deduction_err = || MiddlewareError::invalid_deduction(op.clone(), st.clone());
|
let deduction_err = || MiddlewareError::invalid_deduction(op.clone(), st.clone());
|
||||||
let (root, key, value, pf) = match (op, st) {
|
let (root, key, value, pf) = match (op, st) {
|
||||||
|
|
@ -178,31 +184,42 @@ pub(crate) fn extract_merkle_proofs(
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
aux_list[i] = OperationAux::MerkleProofIndex(table.len());
|
let claim_proof = MerkleClaimAndProof::new(Hash::from(root), key, value, pf.clone());
|
||||||
table.push(MerkleClaimAndProof::new(
|
if pf.existence
|
||||||
Hash::from(root),
|
// TODO: Make sure there's no off-by-one error here
|
||||||
key,
|
&& pf.siblings.len() <= params.containers.max_depth_small
|
||||||
value,
|
&& tables.small.len() < params.containers.state.max_small
|
||||||
pf.clone(),
|
{
|
||||||
));
|
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!(
|
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 ({}).",
|
||||||
table.len(),
|
tables.medium.len(),
|
||||||
params.max_merkle_proofs_containers
|
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.
|
/// 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,
|
params: &Params,
|
||||||
aux_list: &mut [OperationAux],
|
aux_list: &mut [OperationAux],
|
||||||
operations: &[middleware::Operation],
|
operations: &[middleware::Operation],
|
||||||
) -> Result<Vec<MerkleTreeStateTransitionProof>> {
|
) -> Result<MerkleTransitionProofs> {
|
||||||
let mut table = Vec::new();
|
let mut tables = MerkleTransitionProofs::default();
|
||||||
for (i, op) in operations.iter().enumerate() {
|
for (i, op) in operations.iter().enumerate() {
|
||||||
let pf = match op {
|
let pf = match op {
|
||||||
middleware::Operation::ContainerInsertFromEntries(_, _, _, _, pf)
|
middleware::Operation::ContainerInsertFromEntries(_, _, _, _, pf)
|
||||||
|
|
@ -210,17 +227,27 @@ pub(crate) fn extract_merkle_tree_state_transition_proofs(
|
||||||
| middleware::Operation::ContainerDeleteFromEntries(_, _, _, pf) => pf.clone(),
|
| middleware::Operation::ContainerDeleteFromEntries(_, _, _, pf) => pf.clone(),
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
aux_list[i] = OperationAux::MerkleTreeStateTransitionProofIndex(table.len());
|
if pf.op_proof.existence
|
||||||
table.push(pf);
|
// 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!(
|
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 ({}).",
|
||||||
table.len(),
|
tables.medium.len(),
|
||||||
params.max_merkle_tree_state_transition_proofs_containers
|
params.containers.transition.max_medium
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Ok(table)
|
Ok(tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn extract_public_key_of(
|
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 mut aux_list = vec![OperationAux::None; params.max_priv_statements()];
|
||||||
let merkle_proofs =
|
let merkle_proofs =
|
||||||
extract_merkle_proofs(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
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_predicates = extract_custom_predicates(params, inputs.operations)?;
|
||||||
let custom_predicate_verifications = extract_custom_predicate_verifications(
|
let custom_predicate_verifications = extract_custom_predicate_verifications(
|
||||||
params,
|
params,
|
||||||
|
|
@ -537,9 +566,6 @@ impl MainPodProver for Prover {
|
||||||
let signed_bys =
|
let signed_bys =
|
||||||
extract_signatures(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
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 (statements, public_statements) = layout_statements(params, false, &inputs)?;
|
||||||
let operations = process_private_statements_operations(
|
let operations = process_private_statements_operations(
|
||||||
params,
|
params,
|
||||||
|
|
@ -572,20 +598,15 @@ impl MainPodProver for Prover {
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
let mut vd_mt_proofs = Vec::with_capacity(inputs.pods.len());
|
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) {
|
for (pod, vd) in inputs.pods.iter().zip(&verifier_datas) {
|
||||||
vd_mt_proofs.push(if pod.is_main() {
|
vd_mt_proofs.push(if pod.is_main() {
|
||||||
(true, inputs.vd_set.get_vds_proof(vd)?)
|
inputs.vd_set.get_vds_proof(vd)?
|
||||||
} else {
|
} else {
|
||||||
// For intro pods we don't verify inclusion of their vk into the vd set, so we
|
// 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
|
// use a valid vds proof that matches the expected root but not the value to pass
|
||||||
(
|
// the constraints
|
||||||
false,
|
pad_vd_mt_proof.clone()
|
||||||
MerkleClaimAndProof {
|
|
||||||
root: inputs.vd_set.root(),
|
|
||||||
value: RawValue::from(pod.verifier_data_hash()),
|
|
||||||
..MerkleClaimAndProof::empty()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -598,7 +619,7 @@ impl MainPodProver for Prover {
|
||||||
merkle_proofs,
|
merkle_proofs,
|
||||||
public_key_of_sks,
|
public_key_of_sks,
|
||||||
signed_bys,
|
signed_bys,
|
||||||
merkle_tree_state_transition_proofs,
|
merkle_transition_proofs,
|
||||||
custom_predicates_with_mpt_proofs,
|
custom_predicates_with_mpt_proofs,
|
||||||
custom_predicate_verifications,
|
custom_predicate_verifications,
|
||||||
};
|
};
|
||||||
|
|
@ -985,7 +1006,18 @@ pub mod tests {
|
||||||
max_statements: 2,
|
max_statements: 2,
|
||||||
max_public_statements: 1,
|
max_public_statements: 1,
|
||||||
max_input_pods_public_statements: 0,
|
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_public_key_of: 0,
|
||||||
max_custom_predicate_verifications: 0,
|
max_custom_predicate_verifications: 0,
|
||||||
max_custom_predicates: 0,
|
max_custom_predicates: 0,
|
||||||
|
|
@ -1024,11 +1056,20 @@ pub mod tests {
|
||||||
max_custom_predicates: 2,
|
max_custom_predicates: 2,
|
||||||
max_custom_predicate_verifications: 2,
|
max_custom_predicate_verifications: 2,
|
||||||
max_custom_predicate_wildcards: 3,
|
max_custom_predicate_wildcards: 3,
|
||||||
max_merkle_proofs_containers: 2,
|
|
||||||
max_merkle_tree_state_transition_proofs_containers: 2,
|
|
||||||
max_public_key_of: 2,
|
max_public_key_of: 2,
|
||||||
max_depth_mt_containers: 4,
|
|
||||||
max_depth_mt_vds: 6,
|
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();
|
let mut vds = DEFAULT_VD_LIST.clone();
|
||||||
vds.push(rec_main_pod_circuit_data(¶ms).1.verifier_only.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_public_statements: 4,
|
||||||
max_custom_predicate_wildcards: 4,
|
max_custom_predicate_wildcards: 4,
|
||||||
max_custom_predicate_verifications: 2,
|
max_custom_predicate_verifications: 2,
|
||||||
max_merkle_proofs_containers: 3,
|
containers: middleware::ParamsContainers {
|
||||||
max_merkle_tree_state_transition_proofs_containers: 0,
|
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()
|
..Default::default()
|
||||||
};
|
};
|
||||||
println!("{:#?}", params);
|
println!("{:#?}", params);
|
||||||
|
|
@ -1156,8 +1207,18 @@ pub mod tests {
|
||||||
max_public_statements: 2,
|
max_public_statements: 2,
|
||||||
max_custom_predicate_wildcards: 4,
|
max_custom_predicate_wildcards: 4,
|
||||||
max_custom_predicate_verifications: 2,
|
max_custom_predicate_verifications: 2,
|
||||||
max_merkle_proofs_containers: 0,
|
containers: middleware::ParamsContainers {
|
||||||
max_merkle_tree_state_transition_proofs_containers: 0,
|
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()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut vds = DEFAULT_VD_LIST.clone();
|
let mut vds = DEFAULT_VD_LIST.clone();
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
mainpod::{SignedBy, Statement},
|
mainpod::{MerkleProofs, MerkleTransitionProofs, SignedBy, Statement},
|
||||||
primitives::merkletree::{MerkleClaimAndProof, MerkleTreeStateTransitionProof},
|
|
||||||
},
|
},
|
||||||
middleware::{self, OperationType, Params},
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum OperationAux {
|
pub enum OperationAux {
|
||||||
None,
|
None,
|
||||||
MerkleProofIndex(usize),
|
MerkleProofIndex(Size, usize),
|
||||||
|
MerkleTransitionProofIndex(Size, usize),
|
||||||
PublicKeyOfIndex(usize),
|
PublicKeyOfIndex(usize),
|
||||||
SignedByIndex(usize),
|
SignedByIndex(usize),
|
||||||
MerkleTreeStateTransitionProofIndex(usize),
|
|
||||||
CustomPredVerifyIndex(usize),
|
CustomPredVerifyIndex(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperationAux {
|
impl OperationAux {
|
||||||
fn table_offset_merkle_proof(_params: &Params) -> usize {
|
fn table_offset_merkle_proof(params: &Params, size: Size) -> usize {
|
||||||
// At index 0 we store a zero entry
|
match size {
|
||||||
1
|
// At index 0 we store a zero entry
|
||||||
|
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 {
|
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 {
|
fn table_offset_signed_by(params: &Params) -> usize {
|
||||||
Self::table_offset_public_key_of(params) + params.max_public_key_of
|
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 {
|
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_public_key_of
|
||||||
+ params.max_signed_by
|
+ 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 {
|
pub fn table_index(&self, params: &Params) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::None => 0,
|
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::PublicKeyOfIndex(i) => Self::table_offset_public_key_of(params) + *i,
|
||||||
Self::SignedByIndex(i) => Self::table_offset_signed_by(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,
|
Self::CustomPredVerifyIndex(i) => Self::table_offset_custom_pred_verify(params) + *i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,8 +134,8 @@ impl Operation {
|
||||||
&self,
|
&self,
|
||||||
statements: &[Statement],
|
statements: &[Statement],
|
||||||
signatures: &[SignedBy],
|
signatures: &[SignedBy],
|
||||||
merkle_proofs: &[MerkleClaimAndProof],
|
merkle_proofs: &MerkleProofs,
|
||||||
merkle_tree_state_transition_proofs: &[MerkleTreeStateTransitionProof],
|
merkle_transition_proofs: &MerkleTransitionProofs,
|
||||||
) -> Result<crate::middleware::Operation> {
|
) -> Result<crate::middleware::Operation> {
|
||||||
let deref_args = self
|
let deref_args = self
|
||||||
.1
|
.1
|
||||||
|
|
@ -113,17 +151,26 @@ impl Operation {
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
let deref_aux = match self.2 {
|
let deref_aux = match self.2 {
|
||||||
OperationAux::None => crate::middleware::OperationAux::None,
|
OperationAux::None => crate::middleware::OperationAux::None,
|
||||||
OperationAux::CustomPredVerifyIndex(_) => crate::middleware::OperationAux::None,
|
OperationAux::MerkleProofIndex(size, i) => {
|
||||||
OperationAux::MerkleProofIndex(i) => crate::middleware::OperationAux::MerkleProof(
|
let table = match size {
|
||||||
merkle_proofs
|
Size::Small => &merkle_proofs.small,
|
||||||
.get(i)
|
Size::Medium => &merkle_proofs.medium,
|
||||||
.ok_or(Error::custom(format!("Missing Merkle proof index {}", i)))?
|
};
|
||||||
.proof
|
crate::middleware::OperationAux::MerkleProof(
|
||||||
.clone(),
|
table
|
||||||
),
|
.get(i)
|
||||||
OperationAux::MerkleTreeStateTransitionProofIndex(i) => {
|
.ok_or(Error::custom(format!("Missing Merkle proof index {}", i)))?
|
||||||
|
.proof
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
OperationAux::MerkleTransitionProofIndex(size, i) => {
|
||||||
|
let table = match size {
|
||||||
|
Size::Small => &merkle_transition_proofs.small,
|
||||||
|
Size::Medium => &merkle_transition_proofs.medium,
|
||||||
|
};
|
||||||
crate::middleware::OperationAux::MerkleTreeStateTransitionProof(
|
crate::middleware::OperationAux::MerkleTreeStateTransitionProof(
|
||||||
merkle_tree_state_transition_proofs
|
table
|
||||||
.get(i)
|
.get(i)
|
||||||
.ok_or(Error::custom(format!(
|
.ok_or(Error::custom(format!(
|
||||||
"Missing Merkle state transition proof index {}",
|
"Missing Merkle state transition proof index {}",
|
||||||
|
|
@ -132,6 +179,7 @@ impl Operation {
|
||||||
.clone(),
|
.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
OperationAux::CustomPredVerifyIndex(_) => crate::middleware::OperationAux::None,
|
||||||
OperationAux::SignedByIndex(i) => crate::middleware::OperationAux::Signature(
|
OperationAux::SignedByIndex(i) => crate::middleware::OperationAux::Signature(
|
||||||
signatures
|
signatures
|
||||||
.get(i)
|
.get(i)
|
||||||
|
|
@ -165,12 +213,14 @@ impl fmt::Display for Operation {
|
||||||
}
|
}
|
||||||
match self.2 {
|
match self.2 {
|
||||||
OperationAux::None => (),
|
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::CustomPredVerifyIndex(i) => write!(f, " custom_pred_verify_{:02}", i)?,
|
||||||
OperationAux::PublicKeyOfIndex(i) => write!(f, " public_key_of_{:02}", i)?,
|
OperationAux::PublicKeyOfIndex(i) => write!(f, " public_key_of_{:02}", i)?,
|
||||||
OperationAux::SignedByIndex(i) => write!(f, " signed_by_{:02}", i)?,
|
OperationAux::SignedByIndex(i) => write!(f, " signed_by_{:02}", i)?,
|
||||||
OperationAux::MerkleTreeStateTransitionProofIndex(i) => {
|
OperationAux::MerkleTransitionProofIndex(size, i) => {
|
||||||
write!(f, " merkle_tree_state_transition_proof_{:02}", i)?
|
write!(f, " {}_merkle_transition_proof_{:02}", size, i)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,12 @@ use crate::{
|
||||||
basetypes::{Proof, VerifierOnlyCircuitData},
|
basetypes::{Proof, VerifierOnlyCircuitData},
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
mainpod::{
|
mainpod::{
|
||||||
calculate_statements_hash, extract_merkle_proofs,
|
calculate_statements_hash, extract_merkle_proofs, extract_merkle_transition_proofs,
|
||||||
extract_merkle_tree_state_transition_proofs, extract_signatures, layout_statements,
|
extract_signatures, layout_statements, process_private_statements_operations,
|
||||||
process_private_statements_operations, process_public_statements_operations, Operation,
|
process_public_statements_operations, MerkleProofs, MerkleTransitionProofs, Operation,
|
||||||
OperationAux, SignedBy, Statement,
|
OperationAux, SignedBy, Statement,
|
||||||
},
|
},
|
||||||
mock::emptypod::MockEmptyPod,
|
mock::emptypod::MockEmptyPod,
|
||||||
primitives::merkletree::{MerkleClaimAndProof, MerkleTreeStateTransitionProof},
|
|
||||||
recursion::hash_verifier_data,
|
recursion::hash_verifier_data,
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
|
|
@ -45,10 +44,10 @@ pub struct MockMainPod {
|
||||||
operations: Vec<Operation>,
|
operations: Vec<Operation>,
|
||||||
// public subset of the `statements` vector
|
// public subset of the `statements` vector
|
||||||
public_statements: Vec<Statement>,
|
public_statements: Vec<Statement>,
|
||||||
// All Merkle proofs
|
// All Merkle proofs for containers
|
||||||
merkle_proofs_containers: Vec<MerkleClaimAndProof>,
|
merkle_proofs: MerkleProofs,
|
||||||
// All Merkle tree state transition proofs
|
// All Merkle tree state transition proofs for containers
|
||||||
merkle_tree_state_transition_proofs_containers: Vec<MerkleTreeStateTransitionProof>,
|
merkle_transition_proofs: MerkleTransitionProofs,
|
||||||
// All verified signatures
|
// All verified signatures
|
||||||
signatures: Vec<SignedBy>,
|
signatures: Vec<SignedBy>,
|
||||||
}
|
}
|
||||||
|
|
@ -124,8 +123,8 @@ struct Data {
|
||||||
public_statements: Vec<Statement>,
|
public_statements: Vec<Statement>,
|
||||||
operations: Vec<Operation>,
|
operations: Vec<Operation>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
merkle_proofs: Vec<MerkleClaimAndProof>,
|
merkle_proofs: MerkleProofs,
|
||||||
merkle_tree_state_transition_proofs: Vec<MerkleTreeStateTransitionProof>,
|
merkle_transition_proofs: MerkleTransitionProofs,
|
||||||
signatures: Vec<SignedBy>,
|
signatures: Vec<SignedBy>,
|
||||||
input_pods: Vec<(usize, Params, Hash, VDSet, serde_json::Value)>,
|
input_pods: Vec<(usize, Params, Hash, VDSet, serde_json::Value)>,
|
||||||
}
|
}
|
||||||
|
|
@ -153,8 +152,8 @@ impl MockMainPod {
|
||||||
let merkle_proofs =
|
let merkle_proofs =
|
||||||
extract_merkle_proofs(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
extract_merkle_proofs(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
||||||
// Similarly for Merkle state transition proofs.
|
// Similarly for Merkle state transition proofs.
|
||||||
let merkle_tree_state_transition_proofs =
|
let merkle_transition_proofs =
|
||||||
extract_merkle_tree_state_transition_proofs(params, &mut aux_list, inputs.operations)?;
|
extract_merkle_transition_proofs(params, &mut aux_list, inputs.operations)?;
|
||||||
let signatures =
|
let signatures =
|
||||||
extract_signatures(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
extract_signatures(params, &mut aux_list, inputs.operations, inputs.statements)?;
|
||||||
|
|
||||||
|
|
@ -185,8 +184,8 @@ impl MockMainPod {
|
||||||
public_statements,
|
public_statements,
|
||||||
statements,
|
statements,
|
||||||
operations,
|
operations,
|
||||||
merkle_proofs_containers: merkle_proofs,
|
merkle_proofs,
|
||||||
merkle_tree_state_transition_proofs_containers: merkle_tree_state_transition_proofs,
|
merkle_transition_proofs,
|
||||||
signatures,
|
signatures,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -260,8 +259,8 @@ impl Pod for MockMainPod {
|
||||||
.deref(
|
.deref(
|
||||||
&self.statements[..input_statement_offset + i],
|
&self.statements[..input_statement_offset + i],
|
||||||
&self.signatures,
|
&self.signatures,
|
||||||
&self.merkle_proofs_containers,
|
&self.merkle_proofs,
|
||||||
&self.merkle_tree_state_transition_proofs_containers,
|
&self.merkle_transition_proofs,
|
||||||
)?
|
)?
|
||||||
.check_and_log(&self.params, &s.clone().try_into()?)
|
.check_and_log(&self.params, &s.clone().try_into()?)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
|
|
@ -321,10 +320,8 @@ impl Pod for MockMainPod {
|
||||||
public_statements: self.public_statements.clone(),
|
public_statements: self.public_statements.clone(),
|
||||||
operations: self.operations.clone(),
|
operations: self.operations.clone(),
|
||||||
statements: self.statements.clone(),
|
statements: self.statements.clone(),
|
||||||
merkle_proofs: self.merkle_proofs_containers.clone(),
|
merkle_proofs: self.merkle_proofs.clone(),
|
||||||
merkle_tree_state_transition_proofs: self
|
merkle_transition_proofs: self.merkle_transition_proofs.clone(),
|
||||||
.merkle_tree_state_transition_proofs_containers
|
|
||||||
.clone(),
|
|
||||||
signatures: self.signatures.clone(),
|
signatures: self.signatures.clone(),
|
||||||
input_pods,
|
input_pods,
|
||||||
})
|
})
|
||||||
|
|
@ -344,7 +341,7 @@ impl Pod for MockMainPod {
|
||||||
operations,
|
operations,
|
||||||
statements,
|
statements,
|
||||||
merkle_proofs,
|
merkle_proofs,
|
||||||
merkle_tree_state_transition_proofs,
|
merkle_transition_proofs,
|
||||||
signatures,
|
signatures,
|
||||||
input_pods,
|
input_pods,
|
||||||
} = serde_json::from_value(data)?;
|
} = serde_json::from_value(data)?;
|
||||||
|
|
@ -362,8 +359,8 @@ impl Pod for MockMainPod {
|
||||||
public_statements,
|
public_statements,
|
||||||
operations,
|
operations,
|
||||||
statements,
|
statements,
|
||||||
merkle_proofs_containers: merkle_proofs,
|
merkle_proofs,
|
||||||
merkle_tree_state_transition_proofs_containers: merkle_tree_state_transition_proofs,
|
merkle_transition_proofs,
|
||||||
signatures,
|
signatures,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,6 @@ use crate::{
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct MerkleClaimAndProofTarget {
|
pub struct MerkleClaimAndProofTarget {
|
||||||
pub(crate) max_depth: usize,
|
pub(crate) max_depth: usize,
|
||||||
// `enabled` determines if the merkleproof verification is enabled
|
|
||||||
pub(crate) enabled: BoolTarget,
|
|
||||||
pub(crate) root: HashOutTarget,
|
pub(crate) root: HashOutTarget,
|
||||||
pub(crate) key: ValueTarget,
|
pub(crate) key: ValueTarget,
|
||||||
pub(crate) value: ValueTarget,
|
pub(crate) value: ValueTarget,
|
||||||
|
|
@ -121,16 +119,9 @@ pub fn verify_merkle_proof_circuit(
|
||||||
let obtained_root =
|
let obtained_root =
|
||||||
compute_root_from_leaf(max_depth, builder, &path, &leaf_hash, &proof.siblings);
|
compute_root_from_leaf(max_depth, builder, &path, &leaf_hash, &proof.siblings);
|
||||||
|
|
||||||
// check that obtained_root==root (from inputs), when enabled==true
|
// check that obtained_root==root (from inputs)
|
||||||
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();
|
|
||||||
for j in 0..HASH_SIZE {
|
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);
|
measure_gates_end!(builder, measure);
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +130,6 @@ impl MerkleClaimAndProofTarget {
|
||||||
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
||||||
MerkleClaimAndProofTarget {
|
MerkleClaimAndProofTarget {
|
||||||
max_depth,
|
max_depth,
|
||||||
enabled: builder.add_virtual_bool_target_safe(),
|
|
||||||
root: builder.add_virtual_hash(),
|
root: builder.add_virtual_hash(),
|
||||||
key: builder.add_virtual_value(),
|
key: builder.add_virtual_value(),
|
||||||
value: builder.add_virtual_value(),
|
value: builder.add_virtual_value(),
|
||||||
|
|
@ -154,12 +144,7 @@ impl MerkleClaimAndProofTarget {
|
||||||
}
|
}
|
||||||
/// assigns the given values to the targets
|
/// assigns the given values to the targets
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn set_targets(
|
pub fn set_targets(&self, pw: &mut PartialWitness<F>, mp: &MerkleClaimAndProof) -> Result<()> {
|
||||||
&self,
|
|
||||||
pw: &mut PartialWitness<F>,
|
|
||||||
enabled: bool,
|
|
||||||
mp: &MerkleClaimAndProof,
|
|
||||||
) -> Result<()> {
|
|
||||||
if mp.proof.siblings.len() > self.max_depth {
|
if mp.proof.siblings.len() > self.max_depth {
|
||||||
return Err(Error::Tree(TreeError::circuit_depth_too_small(
|
return Err(Error::Tree(TreeError::circuit_depth_too_small(
|
||||||
self.max_depth,
|
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_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.key.elements, &mp.key.0)?;
|
||||||
pw.set_target_arr(&self.value.elements, &mp.value.0)?;
|
pw.set_target_arr(&self.value.elements, &mp.value.0)?;
|
||||||
|
|
@ -207,8 +191,6 @@ impl MerkleClaimAndProofTarget {
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct MerkleProofExistenceTarget {
|
pub struct MerkleProofExistenceTarget {
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
// `enabled` determines if the merkleproof verification is enabled
|
|
||||||
pub(crate) enabled: BoolTarget,
|
|
||||||
pub(crate) root: HashOutTarget,
|
pub(crate) root: HashOutTarget,
|
||||||
pub(crate) key: ValueTarget,
|
pub(crate) key: ValueTarget,
|
||||||
pub(crate) value: ValueTarget,
|
pub(crate) value: ValueTarget,
|
||||||
|
|
@ -236,16 +218,9 @@ pub fn verify_merkle_proof_existence_circuit(
|
||||||
let obtained_root =
|
let obtained_root =
|
||||||
compute_root_from_leaf(max_depth, builder, &path, &leaf_hash, &proof.siblings);
|
compute_root_from_leaf(max_depth, builder, &path, &leaf_hash, &proof.siblings);
|
||||||
|
|
||||||
// check that obtained_root==root (from inputs), when enabled==true
|
// check that obtained_root==root (from inputs)
|
||||||
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();
|
|
||||||
for j in 0..HASH_SIZE {
|
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);
|
measure_gates_end!(builder, measure);
|
||||||
|
|
||||||
|
|
@ -256,7 +231,6 @@ impl MerkleProofExistenceTarget {
|
||||||
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
||||||
MerkleProofExistenceTarget {
|
MerkleProofExistenceTarget {
|
||||||
max_depth,
|
max_depth,
|
||||||
enabled: builder.add_virtual_bool_target_safe(),
|
|
||||||
root: builder.add_virtual_hash(),
|
root: builder.add_virtual_hash(),
|
||||||
key: builder.add_virtual_value(),
|
key: builder.add_virtual_value(),
|
||||||
value: builder.add_virtual_value(),
|
value: builder.add_virtual_value(),
|
||||||
|
|
@ -265,12 +239,7 @@ impl MerkleProofExistenceTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// assigns the given values to the targets
|
/// assigns the given values to the targets
|
||||||
pub fn set_targets(
|
pub fn set_targets(&self, pw: &mut PartialWitness<F>, mp: &MerkleClaimAndProof) -> Result<()> {
|
||||||
&self,
|
|
||||||
pw: &mut PartialWitness<F>,
|
|
||||||
enabled: bool,
|
|
||||||
mp: &MerkleClaimAndProof,
|
|
||||||
) -> Result<()> {
|
|
||||||
assert!(mp.proof.existence); // sanity check
|
assert!(mp.proof.existence); // sanity check
|
||||||
if mp.proof.siblings.len() > self.max_depth {
|
if mp.proof.siblings.len() > self.max_depth {
|
||||||
return Err(Error::Tree(TreeError::circuit_depth_too_small(
|
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_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.key.elements, &mp.key.0)?;
|
||||||
pw.set_target_arr(&self.value.elements, &mp.value.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)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct MerkleTreeStateTransitionProofTarget {
|
pub struct MerkleTreeStateTransitionProofTarget {
|
||||||
pub(crate) max_depth: usize,
|
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) op: Target,
|
||||||
pub(crate) old_root: HashOutTarget,
|
pub(crate) old_root: HashOutTarget,
|
||||||
pub(crate) op_proof: MerkleClaimAndProofTarget,
|
pub(crate) op_proof: MerkleClaimAndProofTarget,
|
||||||
|
|
@ -511,7 +477,6 @@ pub fn verify_merkle_state_transition_circuit(
|
||||||
};
|
};
|
||||||
let new_key_proof = MerkleProofExistenceTarget {
|
let new_key_proof = MerkleProofExistenceTarget {
|
||||||
max_depth: proof.max_depth,
|
max_depth: proof.max_depth,
|
||||||
enabled: proof.enabled,
|
|
||||||
root,
|
root,
|
||||||
key: proof.op_key,
|
key: proof.op_key,
|
||||||
value: proof.op_value,
|
value: proof.op_value,
|
||||||
|
|
@ -523,13 +488,7 @@ pub fn verify_merkle_state_transition_circuit(
|
||||||
// Insert/Delete: Non-existence
|
// Insert/Delete: Non-existence
|
||||||
// Update: Existence
|
// Update: Existence
|
||||||
let proof_type = is_update;
|
let proof_type = is_update;
|
||||||
builder.conditional_assert_eq(
|
builder.connect(proof.op_proof.existence.target, proof_type.target);
|
||||||
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);
|
|
||||||
|
|
||||||
// 4) assert proof_non_existence.root corresponds to the root
|
// 4) assert proof_non_existence.root corresponds to the root
|
||||||
// specified by the op (old_root for Insert/Update and new_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 {
|
for j in 0..HASH_SIZE {
|
||||||
// 4.1) assert that proof.proof_non_existence.root == proof.old_root
|
// 4.1) assert that proof.proof_non_existence.root == proof.old_root
|
||||||
builder.conditional_assert_eq(
|
builder.connect(proof.op_proof.root.elements[j], claim_root.elements[j]);
|
||||||
proof.enabled.target,
|
|
||||||
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).
|
// 4.2) assert that the non-existence proof uses the op_key (value not needed).
|
||||||
builder.conditional_assert_eq(
|
builder.connect(proof.op_proof.key.elements[j], proof.op_key.elements[j]);
|
||||||
proof.enabled.target,
|
|
||||||
proof.op_proof.key.elements[j],
|
|
||||||
proof.op_key.elements[j],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare value for check 5.2)
|
// 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]))
|
.map(|j| builder.select(is_divergence_level, zero, new_siblings[i].elements[j]))
|
||||||
.collect();
|
.collect();
|
||||||
for j in 0..HASH_SIZE {
|
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:
|
// 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);
|
let in_case_5_2 = builder.and(old_is_noteq_new, is_divergence_level);
|
||||||
|
|
||||||
// do the case2's checks
|
// 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 {
|
for j in 0..HASH_SIZE {
|
||||||
builder.conditional_assert_eq(sel.target, old_siblings[i].elements[j], zero);
|
builder.conditional_assert_eq(sel.target, old_siblings[i].elements[j], zero);
|
||||||
builder.conditional_assert_eq(
|
builder.conditional_assert_eq(
|
||||||
|
|
@ -641,7 +592,6 @@ impl MerkleTreeStateTransitionProofTarget {
|
||||||
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
pub fn new_virtual(max_depth: usize, builder: &mut CircuitBuilder<F, D>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
max_depth,
|
max_depth,
|
||||||
enabled: builder.add_virtual_bool_target_safe(),
|
|
||||||
op: builder.add_virtual_target(),
|
op: builder.add_virtual_target(),
|
||||||
|
|
||||||
old_root: builder.add_virtual_hash(),
|
old_root: builder.add_virtual_hash(),
|
||||||
|
|
@ -661,7 +611,6 @@ impl MerkleTreeStateTransitionProofTarget {
|
||||||
pub fn set_targets(
|
pub fn set_targets(
|
||||||
&self,
|
&self,
|
||||||
pw: &mut PartialWitness<F>,
|
pw: &mut PartialWitness<F>,
|
||||||
enabled: bool,
|
|
||||||
mp: &MerkleTreeStateTransitionProof,
|
mp: &MerkleTreeStateTransitionProof,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let new_siblings = mp.siblings.clone();
|
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_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()))?;
|
pw.set_hash_target(self.old_root, HashOut::from_vec(mp.old_root.0.to_vec()))?;
|
||||||
self.op_proof.set_targets(
|
self.op_proof.set_targets(
|
||||||
pw,
|
pw,
|
||||||
enabled,
|
|
||||||
&MerkleClaimAndProof {
|
&MerkleClaimAndProof {
|
||||||
root: if mp.op == MerkleTreeOp::Delete {
|
root: if mp.op == MerkleTreeOp::Delete {
|
||||||
mp.new_root
|
mp.new_root
|
||||||
|
|
@ -859,7 +806,6 @@ pub mod tests {
|
||||||
verify_merkle_proof_circuit(&mut builder, &targets);
|
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||||
targets.set_targets(
|
targets.set_targets(
|
||||||
&mut pw,
|
&mut pw,
|
||||||
true,
|
|
||||||
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -871,6 +817,42 @@ pub mod tests {
|
||||||
Ok(())
|
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]
|
#[test]
|
||||||
fn test_merkleproof_only_existence_verify() -> Result<()> {
|
fn test_merkleproof_only_existence_verify() -> Result<()> {
|
||||||
for max_depth in [10, 16, 32, 40, 64, 128, 130, 250, 256] {
|
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);
|
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||||
targets.set_targets(
|
targets.set_targets(
|
||||||
&mut pw,
|
&mut pw,
|
||||||
true,
|
|
||||||
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -982,7 +963,6 @@ pub mod tests {
|
||||||
verify_merkle_proof_circuit(&mut builder, &targets);
|
verify_merkle_proof_circuit(&mut builder, &targets);
|
||||||
targets.set_targets(
|
targets.set_targets(
|
||||||
&mut pw,
|
&mut pw,
|
||||||
true,
|
|
||||||
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
&MerkleClaimAndProof::new(tree.root(), key, Some(value), proof),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -1028,32 +1008,15 @@ pub mod tests {
|
||||||
|
|
||||||
let targets = MerkleClaimAndProofTarget::new_virtual(max_depth, &mut builder);
|
let targets = MerkleClaimAndProofTarget::new_virtual(max_depth, &mut builder);
|
||||||
verify_merkle_proof_circuit(&mut builder, &targets);
|
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);
|
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
|
// generate proof, expecting it to fail (since we're using the wrong
|
||||||
// root)
|
// root)
|
||||||
let data = builder.build::<C>();
|
let data = builder.build::<C>();
|
||||||
assert!(data.prove(pw).is_err());
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1076,7 +1039,7 @@ pub mod tests {
|
||||||
|
|
||||||
let targets = MerkleTreeStateTransitionProofTarget::new_virtual(max_depth, &mut builder);
|
let targets = MerkleTreeStateTransitionProofTarget::new_virtual(max_depth, &mut builder);
|
||||||
verify_merkle_state_transition_circuit(&mut builder, &targets);
|
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
|
// generate & verify proof
|
||||||
let data = builder.build::<C>();
|
let data = builder.build::<C>();
|
||||||
|
|
@ -1273,71 +1236,4 @@ pub mod tests {
|
||||||
assert_ne!(state_transition_proof.new_root, tree.root()); // Tamper check
|
assert_ne!(state_transition_proof.new_root, tree.root()); // Tamper check
|
||||||
Ok(())
|
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 {
|
pub fn new(root: Hash, key: RawValue, value: Option<RawValue>, proof: MerkleProof) -> Self {
|
||||||
Self {
|
Self {
|
||||||
root,
|
root,
|
||||||
|
|
@ -974,7 +989,6 @@ pub struct MerkleTreeStateTransitionProof {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MerkleTreeStateTransitionProof {
|
impl MerkleTreeStateTransitionProof {
|
||||||
/// Value used for padding.
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
let empty_proof_and_claim = MerkleClaimAndProof::empty();
|
let empty_proof_and_claim = MerkleClaimAndProof::empty();
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -988,6 +1002,20 @@ impl MerkleTreeStateTransitionProof {
|
||||||
siblings: vec![],
|
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
|
// NOTE: currently we use automatic serialization/deserialization, which is
|
||||||
|
|
@ -1165,6 +1193,15 @@ pub mod tests {
|
||||||
Ok(())
|
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]
|
#[test]
|
||||||
fn test_key_not_found() -> Result<()> {
|
fn test_key_not_found() -> Result<()> {
|
||||||
let db = Box::new(db::MemDB::new());
|
let db = Box::new(db::MemDB::new());
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,12 @@ fn aggregate_rows<'a>(
|
||||||
UtilizationRow {
|
UtilizationRow {
|
||||||
name: "merkle proofs",
|
name: "merkle proofs",
|
||||||
used: merkle_proofs,
|
used: merkle_proofs,
|
||||||
limit: params.max_merkle_proofs_containers,
|
limit: params.containers.state.max_medium,
|
||||||
},
|
},
|
||||||
UtilizationRow {
|
UtilizationRow {
|
||||||
name: "merkle state transitions",
|
name: "merkle state transitions",
|
||||||
used: merkle_state_transitions,
|
used: merkle_state_transitions,
|
||||||
limit: params.max_merkle_tree_state_transition_proofs_containers,
|
limit: params.containers.transition.max_medium,
|
||||||
},
|
},
|
||||||
UtilizationRow {
|
UtilizationRow {
|
||||||
name: "custom pred verifications",
|
name: "custom pred verifications",
|
||||||
|
|
@ -278,15 +278,24 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
frontend::multi_pod::cost::CustomPredicateId,
|
frontend::multi_pod::cost::CustomPredicateId,
|
||||||
middleware::{Hash, RawValue},
|
middleware::{Hash, ParamsContainers, ParamsMerkleProofs, RawValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn default_params() -> Params {
|
fn default_params() -> Params {
|
||||||
Params {
|
Params {
|
||||||
max_statements: 48,
|
max_statements: 48,
|
||||||
max_public_statements: 8,
|
max_public_statements: 8,
|
||||||
max_merkle_proofs_containers: 8,
|
containers: ParamsContainers {
|
||||||
max_merkle_tree_state_transition_proofs_containers: 4,
|
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_predicate_verifications: 10,
|
||||||
max_custom_predicates: 2,
|
max_custom_predicates: 2,
|
||||||
max_signed_by: 4,
|
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_statement_groups = lower_bound_from_total(input.num_statements, max_stmts_per_pod);
|
||||||
let lb_merkle = lower_bound_from_total(
|
let lb_merkle = lower_bound_from_total(
|
||||||
resource_totals.merkle_proofs,
|
resource_totals.merkle_proofs,
|
||||||
input.params.max_merkle_proofs_containers,
|
input.params.containers.state.max_medium,
|
||||||
);
|
);
|
||||||
let lb_merkle_transitions = lower_bound_from_total(
|
let lb_merkle_transitions = lower_bound_from_total(
|
||||||
resource_totals.merkle_state_transitions,
|
resource_totals.merkle_state_transitions,
|
||||||
input
|
input.params.containers.transition.max_medium,
|
||||||
.params
|
|
||||||
.max_merkle_tree_state_transition_proofs_containers,
|
|
||||||
);
|
);
|
||||||
let lb_custom_pred_verifications = lower_bound_from_total(
|
let lb_custom_pred_verifications = lower_bound_from_total(
|
||||||
resource_totals.custom_pred_verifications,
|
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])
|
.map(|s| (input.costs[s].merkle_proofs as f64) * prove[s][p])
|
||||||
.sum();
|
.sum();
|
||||||
model.add_constraint(constraint!(
|
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
|
// 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])
|
.map(|s| (input.costs[s].merkle_state_transitions as f64) * prove[s][p])
|
||||||
.sum();
|
.sum();
|
||||||
model.add_constraint(constraint!(
|
model.add_constraint(constraint!(
|
||||||
mst_sum
|
mst_sum <= (input.params.containers.transition.max_medium as f64) * pod_used[p]
|
||||||
<= (input
|
|
||||||
.params
|
|
||||||
.max_merkle_tree_state_transition_proofs_containers as f64)
|
|
||||||
* pod_used[p]
|
|
||||||
));
|
));
|
||||||
|
|
||||||
// 6e: Custom predicate verifications
|
// 6e: Custom predicate verifications
|
||||||
|
|
|
||||||
|
|
@ -780,6 +780,50 @@ pub const BASE_PARAMS: BaseParams = BaseParams {
|
||||||
max_operation_args: 5 + 1,
|
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.
|
/// Params: non dynamic parameters that define the circuit.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[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
|
// max number of operations using custom predicates that can be verified in the MainPod
|
||||||
pub max_custom_predicate_verifications: usize,
|
pub max_custom_predicate_verifications: usize,
|
||||||
pub max_custom_predicate_wildcards: usize,
|
pub max_custom_predicate_wildcards: usize,
|
||||||
// maximum number of merkle proofs used for container operations
|
pub containers: ParamsContainers,
|
||||||
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,
|
|
||||||
// maximum depth of the merkle tree gadget used for verifier_data membership
|
// maximum depth of the merkle tree gadget used for verifier_data membership
|
||||||
// check. This allows creating verifying sets of pod circuits of size
|
// 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,
|
// 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_predicates: 8,
|
||||||
max_custom_predicate_verifications: 8,
|
max_custom_predicate_verifications: 8,
|
||||||
max_custom_predicate_wildcards: 8,
|
max_custom_predicate_wildcards: 8,
|
||||||
max_merkle_proofs_containers: 20,
|
containers: ParamsContainers::default(),
|
||||||
max_merkle_tree_state_transition_proofs_containers: 6,
|
|
||||||
max_depth_mt_containers: 32,
|
|
||||||
max_depth_mt_vds: 6, // up to 64 (2^6) different pod circuits
|
max_depth_mt_vds: 6, // up to 64 (2^6) different pod circuits
|
||||||
max_public_key_of: 2,
|
max_public_key_of: 2,
|
||||||
max_signed_by: 4,
|
max_signed_by: 4,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue