c2pa-rs

A fork of https://github.com/contentauth/c2pa-rs/
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/c2pa-rs.git
Log | Files | Refs | README

merkle.rs (4999B)


      1 // Copyright 2023 Adobe. All rights reserved.
      2 // This file is licensed to you under the Apache License,
      3 // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
      4 // or the MIT license (http://opensource.org/licenses/MIT),
      5 // at your option.
      6 
      7 // Unless required by applicable law or agreed to in writing,
      8 // this software is distributed on an "AS IS" BASIS, WITHOUT
      9 // WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
     10 // implied. See the LICENSE-MIT and LICENSE-APACHE files for the
     11 // specific language governing permissions and limitations under
     12 // each license.
     13 
     14 use extfmt::Hexlify;
     15 
     16 use super::hash_utils::{concat_and_hash, hash_by_alg};
     17 use crate::{Error, Result};
     18 
     19 #[derive(Default, Clone, PartialEq, Debug)]
     20 pub struct MerkleNode(pub Vec<u8>);
     21 
     22 // Implements Merkle tree support corresponding to the C2PA spec variant.  The Merkle tree is not reduced and
     23 // all leaves live at the bottom most level.  If the last layer node is an odd index (lacking a matching pair),
     24 // its node value is propagated to parent layer, no cloning or hashing is expected.  Null tree entries do not contribute to the hashes.
     25 pub struct C2PAMerkleTree {
     26     pub leaves: Vec<MerkleNode>,
     27     pub layers: Vec<Vec<MerkleNode>>,
     28 }
     29 
     30 #[allow(dead_code)]
     31 impl C2PAMerkleTree {
     32     pub fn from_leaves(leaves: Vec<MerkleNode>, alg: &str, hash_leaves: bool) -> C2PAMerkleTree {
     33         let leaves = if hash_leaves {
     34             leaves
     35                 .into_iter()
     36                 .map(|leaf| {
     37                     let hash = hash_by_alg(alg, &leaf.0, None);
     38                     MerkleNode(hash)
     39                 })
     40                 .collect()
     41         } else {
     42             leaves // this handles the case when the leaves are already hashed
     43         };
     44 
     45         let layers = C2PAMerkleTree::generate_tree(alg, &leaves);
     46 
     47         C2PAMerkleTree { leaves, layers }
     48     }
     49 
     50     // generate layer layout
     51     pub fn to_layout(num_leaves: usize) -> Vec<usize> {
     52         let mut layers = Vec::new();
     53 
     54         layers.push(num_leaves);
     55         let mut current_layer = layers[0];
     56 
     57         while current_layer > 1 {
     58             let parent_layer_index = layers.len();
     59             let mut parent_layer_cnt: usize = 0;
     60 
     61             for i in (0..current_layer).step_by(2) {
     62                 if i + 1 == current_layer {
     63                     parent_layer_cnt += 1;
     64                     continue;
     65                 }
     66 
     67                 parent_layer_cnt += 1;
     68             }
     69             layers.push(parent_layer_cnt);
     70             current_layer = layers[parent_layer_index];
     71         }
     72 
     73         layers
     74     }
     75 
     76     pub fn get_root(&self) -> Option<&Vec<u8>> {
     77         Some(&self.layers.last()?.first()?.0)
     78     }
     79 
     80     fn generate_tree(alg: &str, leaves: &[MerkleNode]) -> Vec<Vec<MerkleNode>> {
     81         let mut layers = Vec::new();
     82         layers.push(leaves.to_vec()); // set layer 0
     83         let mut current_layer = &layers[0];
     84 
     85         while current_layer.len() > 1 {
     86             let parent_layer_index = layers.len();
     87             let mut parent_layer = Vec::new();
     88 
     89             for i in (0..current_layer.len()).step_by(2) {
     90                 if i + 1 == current_layer.len() {
     91                     // just pass the current hash since last node is unbalanced
     92                     parent_layer.push(MerkleNode(current_layer[i].0.clone()));
     93                     continue;
     94                 }
     95                 let left = &current_layer[i];
     96                 let right = if i + 1 == current_layer.len() {
     97                     left
     98                 } else {
     99                     &current_layer[i + 1]
    100                 };
    101 
    102                 parent_layer.push(MerkleNode(concat_and_hash(alg, &left.0, Some(&right.0))));
    103             }
    104             layers.push(parent_layer);
    105             current_layer = &layers[parent_layer_index];
    106         }
    107         layers
    108     }
    109 
    110     pub fn get_proof_by_index(&self, leaf_indx: usize) -> Result<Vec<Vec<u8>>> {
    111         if self.leaves.is_empty() || leaf_indx >= self.leaves.len() {
    112             return Err(Error::BadParam(
    113                 "Merkle proof index out of range".to_string(),
    114             ));
    115         }
    116 
    117         let mut proof: Vec<Vec<u8>> = Vec::new();
    118         let mut index = leaf_indx;
    119 
    120         for i in 0..self.layers.len() {
    121             let layer = &self.layers[i];
    122             let is_right = index % 2 == 1;
    123 
    124             if is_right {
    125                 if index - 1 < layer.len() {
    126                     proof.push(layer[index - 1].0.clone());
    127                 }
    128             } else if index + 1 < layer.len() {
    129                 proof.push(layer[index + 1].0.clone());
    130             }
    131             index /= 2;
    132         }
    133         Ok(proof)
    134     }
    135 
    136     pub fn num_layers_required(n: u32) -> i32 {
    137         let f = 1.0 * n as f32;
    138 
    139         f.log2().ceil() as i32
    140     }
    141 
    142     pub fn tree_dump(&self) {
    143         for (i, layer) in self.layers.iter().enumerate() {
    144             println!("Level: {i}");
    145             for (j, mn) in layer.iter().enumerate() {
    146                 println!("{} (Node: {j})", Hexlify(&mn.0));
    147             }
    148         }
    149     }
    150 }