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 = ¤t_layer[i]; 96 let right = if i + 1 == current_layer.len() { 97 left 98 } else { 99 ¤t_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 }