// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright by contributors to this project. // SPDX-License-Identifier: (Apache-2.0 OR MIT)
usecrate::client::MlsError; usecrate::crypto::{CipherSuiteProvider, HpkePublicKey}; usecrate::tree_kem::math as tree_math; usecrate::tree_kem::node::{LeafIndex, Node, NodeIndex}; usecrate::tree_kem::TreeKemPublic; use alloc::vec::Vec; use core::{
fmt::{self, Debug},
ops::Deref,
}; use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize}; use mls_rs_core::error::IntoAnyError; use tree_math::TreeIndex;
usesuper::leaf_node::LeafNodeSource;
#[cfg(feature = "std")] use std::collections::HashSet;
#[cfg(not(feature = "std"))] use alloc::collections::BTreeSet;
// Updates all of the required parent hash values, and returns the calculated parent hash value for the leaf node // If an update path is provided, additionally verify that the calculated parent hash matches #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] pub(crate) asyncfn update_parent_hashes<P: CipherSuiteProvider>(
&mutself,
index: LeafIndex,
verify_leaf_hash: bool,
cipher_suite_provider: &P,
) -> Result<(), MlsError> { // First update the relevant original hashes used for parent hash computation. self.update_hashes(&[index], cipher_suite_provider).await?;
let leaf_hash = self
.parent_hash_for_leaf(cipher_suite_provider, index)
.await?;
let leaf = self.nodes.borrow_as_leaf_mut(index)?;
if verify_leaf_hash { // Verify the parent hash of the new sender leaf node and update the parent hash values // in the local tree iflet LeafNodeSource::Commit(parent_hash) = &leaf.leaf_node_source { if !leaf_hash.matches(parent_hash) { return Err(MlsError::ParentHashMismatch);
}
} else { return Err(MlsError::InvalidLeafNodeSource);
}
} else {
leaf.leaf_node_source = LeafNodeSource::Commit(leaf_hash);
}
// Update hashes after changes to the tree. self.update_hashes(&[index], cipher_suite_provider).await
}
// For each leaf l, validate all non-blank nodes on the chain from l up the tree. for (leaf_index, _) inself.nodes.non_empty_leaves() { letmut n = NodeIndex::from(leaf_index);
whilelet Some(mut ps) = n.parent_sibling(&num_leaves) { // Find the first non-blank ancestor p of n and p's co-path child s. whileself.nodes.is_blank(ps.parent)? { // If we reached the root, we're done with this chain. let Some(ps_parent) = ps.parent.parent_sibling(&num_leaves) else { return Ok(());
};
ps = ps_parent;
}
// Check is n's parent_hash field matches the parent hash of p with co-path child s. let p_parent = self.nodes.borrow_as_parent(ps.parent)?;
let n_node = self
.nodes
.borrow_node(n)?
.as_ref()
.ok_or(MlsError::ExpectedNode)?;
let calculated = ParentHash::new(
cipher_suite_provider,
&p_parent.public_key,
&p_parent.parent_hash,
&original_hashes[ps.sibling as usize],
)
.await?;
if n_node.get_parent_hash() == Some(calculated) { // Check that "n is in the resolution of c, and the intersection of p's unmerged_leaves with the subtree // under c is equal to the resolution of c with n removed". let Some(cp) = ps.sibling.parent_sibling(&num_leaves) else { return Err(MlsError::ParentHashMismatch);
};
let c = cp.sibling; let c_resolution = self.nodes.get_resolution_index(c)?.into_iter();
#[cfg(feature = "std")] let p_unmerged_in_c_subtree = p_unmerged_in_c_subtree.collect::<HashSet<_>>(); #[cfg(not(feature = "std"))] let p_unmerged_in_c_subtree = p_unmerged_in_c_subtree.collect::<BTreeSet<_>>();
if c_resolution.remove(&n)
&& c_resolution == p_unmerged_in_c_subtree
&& nodes_to_validate.remove(&ps.parent)
{ // If n's parent_hash field matches and p has not been validated yet, mark p as validated and continue.
n = ps.parent;
} else { // If p is validated for the second time, the check fails ("all non-blank parent nodes are covered by exactly one such chain"). return Err(MlsError::ParentHashMismatch);
}
} else { // If n's parent_hash field doesn't match, we're done with this chain. break;
}
}
}
// The check passes iff all non-blank nodes are validated. if nodes_to_validate.is_empty() {
Ok(())
} else {
Err(MlsError::ParentHashMismatch)
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.