pub(crate) fn update_path(
        &mut self,
        backend: &impl OpenMlsCryptoProvider,
        sender: LeafIndex,
        update_path: &UpdatePath,
        group_context: &[u8],
        new_leaves_indexes: HashSet<&LeafIndex>,
    ) -> Result<&CommitSecret, TreeError> {
        let own_index = NodeIndex::from(self.own_node_index());

        // Find common ancestor of own leaf and sender leaf
        let common_ancestor_index =
            treemath::common_ancestor_index(NodeIndex::from(sender), own_index);

        // Calculate sender direct path & co-path, common path
        let sender_direct_path = treemath::leaf_direct_path(sender, self.leaf_count())
            .expect("update_path: Error when computing direct path.");
        let sender_co_path = treemath::copath(sender, self.leaf_count())
            .expect("update_path: Error when computing copath.");

        // Find the position of the common ancestor in the sender's direct path
        let common_ancestor_sender_dirpath_index = &sender_direct_path
            .iter()
            .position(|&x| x == common_ancestor_index)
            .unwrap();
        let common_ancestor_copath_index =
            match sender_co_path.get(*common_ancestor_sender_dirpath_index) {
                Some(i) => *i,
                None => return Err(TreeError::InvalidArguments),
            };

        // We can unwrap here, because own index is always within the tree.
        let own_direct_path =
            treemath::leaf_direct_path(self.own_node_index(), self.leaf_count()).unwrap();

        // Resolve the node of that co-path index
        let resolution = self.resolve(common_ancestor_copath_index, &new_leaves_indexes);

        // Figure out the position in the resolution of the node that we have a
        // secret for. We first have to check if our leaf is in the resolution,
        // either due to blanks or due to us being an unmerged leaf.
        let position_in_resolution = match resolution.iter().position(|&x| own_index == x) {
            Some(position) => position,
            // If our leaf is not included, we look again and search for an
            // index in our leaf's direct path.
            None => {
                resolution
                    .iter()
                    .position(|&x| own_direct_path.contains(&x))
                    // We can unwrap here, because regardless of what the resolution
                    // looks like, there has to be a an entry in the resolution that
                    // corresponds to either the own leaf or a node in the direct path.
                    .unwrap()
            }
        };
        // Decrypt the ciphertext of that node
        let common_ancestor_node =
            match update_path.nodes.get(*common_ancestor_sender_dirpath_index) {
                Some(node) => node,
                None => return Err(TreeError::InvalidArguments),
            };
        debug_assert_eq!(
            resolution.len(),
            common_ancestor_node.encrypted_path_secret.len()
        );
        if resolution.len() != common_ancestor_node.encrypted_path_secret.len() {
            return Err(TreeError::InvalidUpdatePath);
        }
        let hpke_ciphertext = &common_ancestor_node.encrypted_path_secret[position_in_resolution];

        // Get the HPKE private key.
        // It's either the own key or must be in the path of the private tree.
        let private_key = if resolution[position_in_resolution] == own_index {
            self.private_tree.hpke_private_key()
        } else {
            match self
                .private_tree
                .path_keys()
                .get(resolution[position_in_resolution])
            {
                Some(k) => k,
                None => return Err(TreeError::InvalidArguments),
            }
        };

        // Compute the common path between the common ancestor and the root
        let common_path = treemath::parent_direct_path(common_ancestor_index, self.leaf_count())
            .expect("update_path: Error when computing direct path.");

        debug_assert!(
            sender_direct_path.len() >= common_path.len(),
            "Library error. Direct path cannot be shorter than common path."
        );

        // Decrypt the secret and derive path secrets
        let secret_bytes = self.ciphersuite.hpke_open(
            backend.crypto(),
            hpke_ciphertext,
            private_key,
            group_context,
            &[],
        )?;
        let path_secret =
            Secret::from_slice(&secret_bytes, ProtocolVersion::default(), self.ciphersuite).into();
        // Derive new path secrets and generate keypairs
        let new_path_public_keys = self.private_tree.continue_path_secrets(
            self.ciphersuite,
            backend,
            path_secret,
            &common_path,
        );

        // Extract public keys from UpdatePath
        let update_path_public_keys: Vec<HpkePublicKey> = update_path
            .nodes
            .iter()
            .map(|node| node.public_key.clone())
            .collect();

        // Check that the public keys are consistent with the update path.
        let (_, common_public_keys) =
            update_path_public_keys.split_at(update_path_public_keys.len() - common_path.len());

        if new_path_public_keys != common_public_keys {
            return Err(TreeError::InvalidUpdatePath);
        }

        // Merge new nodes into the tree
        self.merge_direct_path_keys(update_path, sender_direct_path)?;
        self.merge_public_keys(&new_path_public_keys, &common_path)?;
        self.nodes[sender] = Node::new_leaf(Some(update_path.leaf_key_package.clone()));
        // Calculate and set the parent hashes
        self.set_parent_hashes(backend, sender);

        // TODO: Do we really want to return the commit secret here?

        // We can unwrap here, because we know the commit secret was set via
        // ´continue_path_secrets´.
        Ok(self.private_tree.commit_secret().unwrap())
    }
/// 7.7. Update Paths
///
/// Update the path for incoming commits.
///
/// > The path contains a public key and encrypted secret value for all
/// > intermediate nodes in the path above the leaf. The path is ordered
/// > from the closest node to the leaf to the root; each node MUST be the
/// > parent of its predecessor.


> The path contains a public key and encrypted secret value for all
> intermediate nodes in the path above the leaf. The path is ordered
> from the closest node to the leaf to the root; each node MUST be the
> parent of its predecessor.
> The path contains a public key and encrypted secret value for all > intermediate nodes in the path above the leaf . The path is ordered > from the closest node to the leaf to the root ; each node MUST be the > parent of its predecessor .
pub(crate) fn update_path(
        &mut self,
        backend: &impl OpenMlsCryptoProvider,
        sender: LeafIndex,
        update_path: &UpdatePath,
        group_context: &[u8],
        new_leaves_indexes: HashSet<&LeafIndex>,
    ) -> Result<&CommitSecret, TreeError> {
        let own_index = NodeIndex::from(self.own_node_index());
        // Find common ancestor of own leaf and sender leaf
        let common_ancestor_index =
            treemath::common_ancestor_index(NodeIndex::from(sender), own_index);
        // Calculate sender direct path & co-path, common path
        let sender_direct_path = treemath::leaf_direct_path(sender, self.leaf_count())
            .expect("update_path: Error when computing direct path.");
        let sender_co_path = treemath::copath(sender, self.leaf_count())
            .expect("update_path: Error when computing copath.");
        // Find the position of the common ancestor in the sender's direct path
        let common_ancestor_sender_dirpath_index = &sender_direct_path
            .iter()
            .position(|&x| x == common_ancestor_index)
            .unwrap();
        let common_ancestor_copath_index =
            match sender_co_path.get(*common_ancestor_sender_dirpath_index) {
                Some(i) => *i,
                None => return Err(TreeError::InvalidArguments),
            };
        // We can unwrap here, because own index is always within the tree.
        let own_direct_path =
            treemath::leaf_direct_path(self.own_node_index(), self.leaf_count()).unwrap();
        // Resolve the node of that co-path index
        let resolution = self.resolve(common_ancestor_copath_index, &new_leaves_indexes);
        // Figure out the position in the resolution of the node that we have a
        // secret for. We first have to check if our leaf is in the resolution,
        // either due to blanks or due to us being an unmerged leaf.
        let position_in_resolution = match resolution.iter().position(|&x| own_index == x) {
            Some(position) => position,
            // If our leaf is not included, we look again and search for an
            // index in our leaf's direct path.
            None => {
                resolution
                    .iter()
                    .position(|&x| own_direct_path.contains(&x))
                    // We can unwrap here, because regardless of what the resolution
                    // looks like, there has to be a an entry in the resolution that
                    // corresponds to either the own leaf or a node in the direct path.
                    .unwrap()
            }
        };
        // Decrypt the ciphertext of that node
        let common_ancestor_node =
            match update_path.nodes.get(*common_ancestor_sender_dirpath_index) {
                Some(node) => node,
                None => return Err(TreeError::InvalidArguments),
            };
        debug_assert_eq!(
            resolution.len(),
            common_ancestor_node.encrypted_path_secret.len()
        );
        if resolution.len() != common_ancestor_node.encrypted_path_secret.len() {
            return Err(TreeError::InvalidUpdatePath);
        }
        let hpke_ciphertext = &common_ancestor_node.encrypted_path_secret[position_in_resolution];
        // Get the HPKE private key.
        // It's either the own key or must be in the path of the private tree.
        let private_key = if resolution[position_in_resolution] == own_index {
            self.private_tree.hpke_private_key()
        } else {
            match self
                .private_tree
                .path_keys()
                .get(resolution[position_in_resolution])
            {
                Some(k) => k,
                None => return Err(TreeError::InvalidArguments),
            }
        };
        // Compute the common path between the common ancestor and the root
        let common_path = treemath::parent_direct_path(common_ancestor_index, self.leaf_count())
            .expect("update_path: Error when computing direct path.");
        debug_assert!(
            sender_direct_path.len() >= common_path.len(),
            "Library error. Direct path cannot be shorter than common path."
        );
        // Decrypt the secret and derive path secrets
        let secret_bytes = self.ciphersuite.hpke_open(
            backend.crypto(),
            hpke_ciphertext,
            private_key,
            group_context,
            &[],
        )?;
        let path_secret =
            Secret::from_slice(&secret_bytes, ProtocolVersion::default(), self.ciphersuite).into();
        // Derive new path secrets and generate keypairs
        let new_path_public_keys = self.private_tree.continue_path_secrets(
            self.ciphersuite,
            backend,
            path_secret,
            &common_path,
        );
        // Extract public keys from UpdatePath
        let update_path_public_keys: Vec<HpkePublicKey> = update_path
            .nodes
            .iter()
            .map(|node| node.public_key.clone())
            .collect();
        // Check that the public keys are consistent with the update path.
        let (_, common_public_keys) =
            update_path_public_keys.split_at(update_path_public_keys.len() - common_path.len());
        if new_path_public_keys != common_public_keys {
            return Err(TreeError::InvalidUpdatePath);
        }
        // Merge new nodes into the tree
        self.merge_direct_path_keys(update_path, sender_direct_path)?;
        self.merge_public_keys(&new_path_public_keys, &common_path)?;
        self.nodes[sender] = Node::new_leaf(Some(update_path.leaf_key_package.clone()));
        // Calculate and set the parent hashes
        self.set_parent_hashes(backend, sender);
        // TODO: Do we really want to return the commit secret here?
        // We can unwrap here, because we know the commit secret was set via
        // ´continue_path_secrets´.
        Ok(self.private_tree.commit_secret().unwrap())
    }
pub ( crate ) fn update_path ( & mut self , backend : & impl OpenMlsCryptoProvider , sender : LeafIndex , update_path : & UpdatePath , group_context : & [ u8 ] , new_leaves_indexes : HashSet < & LeafIndex > , ) -> Result < & CommitSecret , TreeError > { let own_index = NodeIndex :: from ( self . own_node_index ( ) ) ; // Find common ancestor of own leaf and sender leaf let common_ancestor_index = treemath :: common_ancestor_index ( NodeIndex :: from ( sender ) , own_index ) ; // Calculate sender direct path & co-path, common path let sender_direct_path = treemath :: leaf_direct_path ( sender , self . leaf_count ( ) ) . expect ( " " ) ; let sender_co_path = treemath :: copath ( sender , self . leaf_count ( ) ) . expect ( " " ) ; // Find the position of the common ancestor in the sender's direct path let common_ancestor_sender_dirpath_index = & sender_direct_path . iter ( ) . position ( | & x | x == common_ancestor_index ) . unwrap ( ) ; let common_ancestor_copath_index = match sender_co_path . get ( * common_ancestor_sender_dirpath_index ) { Some ( i ) => * i , None => return Err ( TreeError :: InvalidArguments ) , } ; // We can unwrap here, because own index is always within the tree. let own_direct_path = treemath :: leaf_direct_path ( self . own_node_index ( ) , self . leaf_count ( ) ) . unwrap ( ) ; // Resolve the node of that co-path index let resolution = self . resolve ( common_ancestor_copath_index , & new_leaves_indexes ) ; // Figure out the position in the resolution of the node that we have a // secret for. We first have to check if our leaf is in the resolution, // either due to blanks or due to us being an unmerged leaf. let position_in_resolution = match resolution . iter ( ) . position ( | & x | own_index == x ) { Some ( position ) => position , // If our leaf is not included, we look again and search for an // index in our leaf's direct path. None => { resolution . iter ( ) . position ( | & x | own_direct_path . contains ( & x ) ) // We can unwrap here, because regardless of what the resolution // looks like, there has to be a an entry in the resolution that // corresponds to either the own leaf or a node in the direct path. . unwrap ( ) } } ; // Decrypt the ciphertext of that node let common_ancestor_node = match update_path . nodes . get ( * common_ancestor_sender_dirpath_index ) { Some ( node ) => node , None => return Err ( TreeError :: InvalidArguments ) , } ; debug_assert_eq ! ( resolution len ( ) common_ancestor_node encrypted_path_secret len ( ) ) ; if resolution . len ( ) != common_ancestor_node . encrypted_path_secret . len ( ) { return Err ( TreeError :: InvalidUpdatePath ) ; } let hpke_ciphertext = & common_ancestor_node . encrypted_path_secret [ position_in_resolution ] ; // Get the HPKE private key. // It's either the own key or must be in the path of the private tree. let private_key = if resolution [ position_in_resolution ] == own_index { self . private_tree . hpke_private_key ( ) } else { match self . private_tree . path_keys ( ) . get ( resolution [ position_in_resolution ] ) { Some ( k ) => k , None => return Err ( TreeError :: InvalidArguments ) , } } ; // Compute the common path between the common ancestor and the root let common_path = treemath :: parent_direct_path ( common_ancestor_index , self . leaf_count ( ) ) . expect ( " " ) ; debug_assert ! ( sender_direct_path len ( ) common_path len ( ) " " ) ; // Decrypt the secret and derive path secrets let secret_bytes = self . ciphersuite . hpke_open ( backend . crypto ( ) , hpke_ciphertext , private_key , group_context , & [ ] , ) ? ; let path_secret = Secret :: from_slice ( & secret_bytes , ProtocolVersion :: default ( ) , self . ciphersuite ) . into ( ) ; // Derive new path secrets and generate keypairs let new_path_public_keys = self . private_tree . continue_path_secrets ( self . ciphersuite , backend , path_secret , & common_path , ) ; // Extract public keys from UpdatePath let update_path_public_keys : Vec < HpkePublicKey > = update_path . nodes . iter ( ) . map ( | node | node . public_key . clone ( ) ) . collect ( ) ; // Check that the public keys are consistent with the update path. let ( _ , common_public_keys ) = update_path_public_keys . split_at ( update_path_public_keys . len ( ) - common_path . len ( ) ) ; if new_path_public_keys != common_public_keys { return Err ( TreeError :: InvalidUpdatePath ) ; } // Merge new nodes into the tree self . merge_direct_path_keys ( update_path , sender_direct_path ) ? ; self . merge_public_keys ( & new_path_public_keys , & common_path ) ? ; self . nodes [ sender ] = Node :: new_leaf ( Some ( update_path . leaf_key_package . clone ( ) ) ) ; // Calculate and set the parent hashes self . set_parent_hashes ( backend , sender ) ; // TODO: Do we really want to return the commit secret here? // We can unwrap here, because we know the commit secret was set via // ´continue_path_secrets´. Ok ( self . private_tree . commit_secret ( ) . unwrap ( ) ) }
7.7.
7 . 7 .
&mut self
backend
&impl OpenMlsCryptoProvider
sender
LeafIndex
update_path
&UpdatePath
group_context
&[u8]
new_leaves_indexes
HashSet<&LeafIndex>
&mut self
backend
&impl OpenMlsCryptoProvider
sender
LeafIndex
update_path
&UpdatePath
group_context
&[u8]
new_leaves_indexes
HashSet<&LeafIndex>