aqua_verifier/
util.rs

1use crate::look_up::look_up::get_tx_data;
2use aqua_verifier_rs_types::crypt;
3use aqua_verifier_rs_types::models::content::RevisionContent;
4use aqua_verifier_rs_types::models::hash::Hash;
5use aqua_verifier_rs_types::models::metadata::RevisionMetadata;
6use aqua_verifier_rs_types::models::public_key::PublicKey;
7use aqua_verifier_rs_types::models::revision::Revision;
8use aqua_verifier_rs_types::models::signature::RevisionSignature;
9use aqua_verifier_rs_types::models::signature::Signature;
10use aqua_verifier_rs_types::models::timestamp::Timestamp;
11use aqua_verifier_rs_types::models::tx_hash::TxHash;
12use aqua_verifier_rs_types::models::witness::{MerkleNode, RevisionWitness};
13use ethers::utils::hash_message;
14use sha3::{Digest, Sha3_512};
15use tokio::runtime::Runtime;
16use std::collections::BTreeMap;
17use std::str;
18use std::str::FromStr;
19
20use crate::model::{ResultStatusEnum, RevisionVerificationResult};
21
22/// Struct to hold the result of file verification.
23#[derive(Debug)]
24pub struct VerifyFileResult {
25    /// The hash of the verified file if successful.
26    pub file_hash: Option<String>,
27    /// Error message if verification fails.
28    pub error_message: Option<String>,
29    /// Logs of the verification process.
30    pub logs: Vec<String>,
31}
32
33
34
35/// Generates a SHA3-512 hash sum from the given content.
36///
37/// # Arguments
38///
39/// * `content` - A string slice containing the content to hash.
40///
41/// # Returns
42///
43/// A hexadecimal representation of the SHA3-512 hash as a String.
44///
45/// # Example
46///
47/// ```
48/// let hash = get_hash_sum("hello world");
49/// println!("Hash: {}", hash);
50/// ```
51pub fn get_hash_sum(content: &str) -> String {
52    if content.is_empty() {
53        String::new()
54    } else {
55        let mut hasher = Sha3_512::new();
56        hasher.update(content.as_bytes());
57        format!("{:x}", hasher.finalize())
58    }
59}
60
61
62/// Generates a SHA3-512 hash from a Base64-encoded string.
63///
64/// # Parameters
65/// 
66/// * `b64` - A string slice that holds the Base64-encoded input.
67///
68/// # Returns
69///
70/// Returns an `Option<Vec<u8>>`. If the decoding is successful, it returns 
71/// `Some` containing the hash as a vector of bytes. If decoding fails, 
72/// it returns `None`.
73fn generate_hash_from_base64(b64: &str) -> Option<Vec<u8>> {
74    // Decode the Base64 string
75    let decoded_bytes_result = base64::decode(b64); //.expect("Failed to decode Base64 string");
76
77    if decoded_bytes_result.is_err() {
78        println!("unable t decode bytes.");
79        return None;
80    }
81    let decoded_bytes = decoded_bytes_result.unwrap();
82
83    // Create a Sha3_512 hasher
84    let mut hasher = Sha3_512::new();
85
86    // Write input data
87    hasher.update(&decoded_bytes);
88
89    // Read hash digest and consume hasher
90    let result = hasher.finalize();
91
92    // Return the hash as a vector of bytes
93    Some(result.to_vec())
94}
95
96/// Verifies the file content against its expected hash.
97///
98/// # Parameters
99///
100/// * `data` - A `RevisionContent` struct containing the file data and expected hash.
101///
102/// # Returns
103///
104/// Returns a tuple containing:
105/// - A boolean indicating whether the verification was successful.
106/// - A `VerifyFileResult` struct with details about the verification process.
107pub fn verify_file_util(data: RevisionContent) -> (bool, VerifyFileResult) {
108    let mut logs: Vec<String> = Vec::new();
109
110    let file_content_hash = data.content.file_hash;
111    let file_content = data.file.unwrap().data;
112    let hash_fromb64 = generate_hash_from_base64(file_content.to_string().as_str());
113
114    if hash_fromb64.is_none() {
115        logs.push("Error : unable to decode bytes in  verifying revision content ".to_string());
116        return (
117            false,
118            VerifyFileResult {
119                file_hash: None,
120                error_message: Some("unable to decode bytes ".to_string()),
121                logs: logs,
122            },
123        );
124    }
125
126    let hash_gen = hex::encode(hash_fromb64.unwrap());
127
128    // logs.push(format!("Info : Hash generated {}", hash_gen));
129    // logs.push(format!("Info : file Hash in chain  {}", file_content_hash.to_string()));
130    if file_content_hash.to_string() != hash_gen {
131        logs.push("Error :  File content hash does not match the genrated hash".to_string());
132        return (
133            false,
134            VerifyFileResult {
135                file_hash: None,
136                error_message: Some("File content hash does not match ".to_string()),
137                logs: logs,
138            },
139        );
140    }
141    logs.push("Sucess  :  File content hash does matches the genrated hash".to_string());
142    (
143        true,
144        VerifyFileResult {
145            file_hash: Some(file_content_hash.to_string()),
146            error_message: None,
147            logs: logs,
148        },
149    )
150}
151
152/// Verifies that the content's hash matches the expected content hash.
153///
154/// # Parameters
155///
156/// * `data` - A reference to a `RevisionContent` struct containing the content to verify.
157///
158/// # Returns
159///
160/// Returns a tuple containing:
161/// - A boolean indicating whether the verification was successful.
162/// - A string representation of the computed content hash.
163pub fn verify_content_util(data: &RevisionContent) -> (bool, String) {
164    let mut content = String::new();
165    content += format!("{:#?}", data.content.file_hash).as_str();
166
167    let content_hash = get_hash_sum(&content);
168    let data_content_hash_str = format!("{:#?}", data.content_hash);
169    if content_hash == data_content_hash_str {
170        (true, content_hash)
171    } else {
172        (false, "Content hash does not match".to_string())
173    }
174}
175
176/// Verifies that the metadata matches its expected hash.
177///
178/// # Parameters
179///
180/// * `data` - A reference to a `RevisionMetadata` struct containing metadata to verify.
181///
182/// # Returns
183///
184/// Returns a tuple containing:
185/// - A boolean indicating whether the verification was successful.
186/// - A string representation of the computed metadata hash.
187pub fn verify_metadata_util(data: &RevisionMetadata) -> (bool, String) {
188    // let metadata_hash = calculate_metadata_hash(
189    //     data.domain_id.clone(),
190    //     data.time_stamp.clone(),
191    //     data.previous_verification_hash,
192    //     data.merge_hash,
193    // );
194    let metadata_hash = metadata_hash(
195        data.domain_id.clone().as_str(),
196        &data.time_stamp.clone(),
197        data.previous_verification_hash.as_ref(),
198    );
199    println!("Metadata hash generated {}", metadata_hash);
200    println!("Metadata hash stored {}", data.metadata_hash.to_string());
201
202    if metadata_hash.to_string() == data.metadata_hash.to_string() {
203        (true, metadata_hash.to_string())
204    } else {
205        (false, "Metadata hash does not match".to_string())
206    }
207}
208
209
210/// Calculates a metadata hash based on domain ID, timestamp, and optional hashes.
211///
212/// # Parameters
213///
214/// * `domain_id` - The domain identifier as a string.
215/// * `timestamp` - The timestamp associated with the metadata.
216/// * `previous_verification_hash` - An optional previous verification hash.
217/// * `merge_hash` - An optional merge hash.
218///
219/// # Returns
220///
221/// Returns a string representing the computed metadata hash.
222pub fn calculate_metadata_hash(
223    domain_id: String,
224    timestamp: Timestamp,
225    previous_verification_hash: Option<Hash>,
226    merge_hash: Option<Hash>,
227) -> String {
228    let mut content: String = domain_id + &timestamp.to_string();
229    if let Some(prev_hash) = previous_verification_hash {
230        content += &prev_hash.to_string();
231    }
232    if let Some(merge) = merge_hash {
233        content += &merge.to_string();
234    }
235    get_hash_sum(&content)
236}
237
238///! Verification utilities for digital signatures, witness data, and content integrity.
239///! 
240///! This module provides functionality for:
241///! - Verifying digital signatures against provided verification hashes
242///! - Validating witness data and merkle proofs
243///! - Computing and verifying various types /// Verifies witness data and optionally checks merkle proof integrity.
244/// 
245/// # Arguments
246/// * `witness_data` - The witness data containing merkle proof and transaction information
247/// * `verification_hash` - The hash to verify against
248/// * `do_verify_merkle_proof` - Whether to verify the merkle proof
249/// * `verification_platform` - The platform to use for verification
250/// * `chain` - The blockchain network to use
251/// * `api_key` - API key for the verification platform
252/// 
253/// # Returns
254/// A tuple containing:
255/// * `bool` - Whether the witness data is valid
256/// * `String` - A status message
257/// * `Vec<String>` - Logs from the verification processof hashes (content, metadata, witness, etc.)
258///! - Managing revision verification chains
259///!
260///! # Examples
261///! ```rust
262///! let signature_data = RevisionSignature { /* ... */ };
263///! let verification_hash = Hash::new("...");
264///! let (is_valid, status) = verify_signature_util(signature_data, verification_hash);
265///! ```
266
267#[warn(unused_assignments)]
268
269/// Verifies a digital signature against a provided verification hash.
270/// 
271/// # Arguments
272/// * `data` - The signature data containing the signature and wallet address
273/// * `verification_hash` - The hash to verify against
274/// 
275/// # Returns
276/// A tuple containing:
277/// * `bool` - Whether the signature is valid
278/// * `String` - A status message describing the verification result
279pub fn verify_signature_util(data: RevisionSignature, verification_hash: Hash) -> (bool, String) {
280    if verification_hash.is_empty() {
281        return (false, "Verification hash must not be empty".to_string());
282    }
283
284    let padded_message = format!(
285        "I sign the following page verification_hash: [0x{}]",
286        verification_hash
287    );
288
289    let signature_string = format!("{:?}", data.signature);
290    println!("The signature is {}", signature_string);
291
292    let mut status = String::new();
293    let mut signature_ok = false;
294    match (
295        hash_message(padded_message),
296        ethers::types::Signature::from_str(signature_string.as_str()),
297    ) {
298        (hashed_msg, Ok(sig)) => {
299            println!("Gen signature {}", sig.clone());
300
301            // let clean_input_1 = if sig.to_string().to_lowercase().starts_with("0x") {
302            //     sig.to_string().to_lowercase()[2..].to_string()
303            // } else {
304            //     sig.to_string().to_lowercase()
305            // };
306            // let clean_input_2 = if signature_string.to_lowercase().starts_with("0x") {
307            //     signature_string.to_lowercase()[2..].to_string()
308            // } else {
309            //     signature_string.to_lowercase()
310            // };
311
312            // signature_ok = clean_input_1 == clean_input_2;
313
314            // status = if signature_ok {
315            //     "Signature is Valid".to_string()
316            // } else {
317            //     "Signature is invalid".to_string()
318            // };
319
320            //todo to be reviewed
321            match ethers::core::types::Signature::recover(&sig, hashed_msg) {
322                Ok(recovered_address_long) => {
323                    let recovered_address = format!("{:?}", recovered_address_long);
324                    let clean_input_1 = if recovered_address
325                        .to_string()
326                        .to_lowercase()
327                        .starts_with("0x")
328                    {
329                        recovered_address.to_string().to_lowercase()[2..].to_string()
330                    } else {
331                        recovered_address.to_string().to_lowercase()
332                    };
333                    let clean_input_2 = if data
334                        .wallet_address
335                        .to_string()
336                        .to_lowercase()
337                        .starts_with("0x")
338                    {
339                        data.wallet_address.to_string().to_lowercase()[2..].to_string()
340                    } else {
341                        data.wallet_address.to_string().to_lowercase()
342                    };
343
344                    println!("1 {:#?}", clean_input_1);
345                    println!("2 {:#?}", clean_input_2);
346
347                    signature_ok = clean_input_1 == clean_input_2;
348                    // signature_ok = recovered_address.to_string().to_lowercase()
349                    //     == data.wallet_address.to_string().to_lowercase();
350
351                    status = if signature_ok {
352                        "Signature is Valid".to_string()
353                    } else {
354                        "Signature is invalid".to_string()
355                    };
356                }
357                Err(e) => {
358                    status = format!("An error occurred retrieving signature: {}", e);
359                }
360            }
361        }
362        (_, Err(e)) => {
363            // Handle invalid signature format
364            status = format!("Invalid signature format: {}", e);
365        }
366    }
367
368    (signature_ok, status)
369}
370
371
372/// Verifies witness data and optionally checks merkle proof integrity.
373/// 
374/// # Arguments
375/// * `witness_data` - The witness data containing merkle proof and transaction information
376/// * `verification_hash` - The hash to verify against
377/// * `do_verify_merkle_proof` - Whether to verify the merkle proof
378/// * `verification_platform` - The platform to use for verification
379/// * `chain` - The blockchain network to use
380/// * `api_key` - API key for the verification platform
381/// 
382/// # Returns
383/// A tuple containing:
384/// * `bool` - Whether the witness data is valid
385/// * `String` - A status message
386/// * `Vec<String>` - Logs from the verification process
387pub fn verify_witness_util(
388    witness_data: RevisionWitness,
389    verification_hash: String,
390    do_verify_merkle_proof: bool,
391    verification_platform: String,
392    chain: String,
393    api_key: String,
394) -> (bool, String, Vec<String>) {
395    let logs = Vec::new();
396
397    let actual_witness_event_verification_hash = get_hash_sum(
398        &(witness_data
399            .domain_snapshot_genesis_hash
400            .clone()
401            .to_string()
402            + &witness_data.merkle_root.to_string()),
403    );
404
405    if actual_witness_event_verification_hash
406        != witness_data.witness_event_verification_hash.to_string()
407    {
408        return (false, "Verification hashes do not match".to_string(), logs);
409    }
410
411    if do_verify_merkle_proof {
412        println!("Doing merkle verification: ");
413        if verification_hash == witness_data.domain_snapshot_genesis_hash.to_string() {
414            return (
415                true,
416                "Verification hash is the same as domain snapshot genesis hash".to_string(),
417                logs
418            );
419        } else {
420            let merkle_proof_is_ok =
421                verify_merkle_integrity(&witness_data.structured_merkle_proof, verification_hash);
422            return (
423                merkle_proof_is_ok,
424                if merkle_proof_is_ok {
425                    "Merkle proof is OK".to_string()
426                } else {
427                    "Error verifying merkle proof".to_string()
428                },
429                logs
430            );
431        }
432    }
433
434    if  verification_platform == "none"{
435        println!("No verificaton platform: ");
436        (true, "Look up not performed.".to_string(), logs)
437    }else{
438        println!("Verification platform found: ");
439    let tx_hash = witness_data.witness_event_transaction_hash.clone();
440    let tx_hash_string = format!("{}", tx_hash);
441    let tx_hash_par = tx_hash_string.as_str();
442    // Create a new runtime
443    let rt = Runtime::new().unwrap();
444
445     // Block on the async function to get its result
446    let get_tx_data_res = rt.block_on( get_tx_data(
447        tx_hash_par,
448        verification_platform,
449        chain,
450        api_key,
451    ));
452
453    let (input_data, _) = get_tx_data_res.unwrap();
454    let witness_event_verification_hash  = format!("{}", witness_data.witness_event_verification_hash);
455
456    println!("Data received from getting tx information: {:#?} \n verification hash: {}", input_data, witness_event_verification_hash);
457
458    if input_data == witness_event_verification_hash {
459        (true, "Look up performed.".to_string(), logs)
460    }else{
461        (false, "Look up failed.".to_string(), logs)
462    }
463
464}
465    // TODO: Implement the checkTransaction function
466   
467}
468
469/// Verifies the integrity of a merkle proof.
470/// 
471/// # Arguments
472/// * `merkle_branch` - The merkle proof branch nodes
473/// * `verification_hash` - The hash to verify against
474/// 
475/// # Returns
476/// `bool` - Whether the merkle proof is valid
477pub fn verify_merkle_integrity(merkle_branch: &[MerkleNode], verification_hash: String) -> bool {
478    if merkle_branch.is_empty() {
479        return false;
480    }
481
482    //todo
483    // let mut prev_successor: Option<Hash> = None;
484    // for node in merkle_branch {
485    //     let leaves = [node.left_leaf.clone(), node.right_leaf.clone()];
486    //     if let Some(ref prev_succ) = prev_successor {
487    //         if !leaves.contains(prev_succ) {
488    //             return false;
489    //         }
490    //     } else {
491    //         if !leaves.contains(&Some(verification_hash.to_string())) {
492    //             return false;
493    //         }
494    //     }
495
496    //     let calculated_successor = if node.left_leaf.is_none() {
497    //         node.right_leaf.clone()
498    //     } else if node.right_leaf.is_none() {
499    //         node.left_leaf.clone()
500    //     } else {
501    //         Some(get_hash_sum(&(node.left_leaf.as_ref().unwrap() + node.right_leaf.as_ref().unwrap())))
502    //     };
503
504    //     if calculated_successor != Some(node.successor.clone()) {
505    //         return false;
506    //     }
507
508    //     prev_successor = Some(node.successor.clone());
509    // }
510
511    true
512}
513
514
515/// Checks if all verifications in a revision result are successful.
516/// 
517/// # Arguments
518/// * `revision_result` - The revision verification result containing multiple verification statuses
519/// 
520/// # Returns
521/// `bool` - Whether all available verifications were successful
522pub fn all_successful_verifications(revision_result: &RevisionVerificationResult) -> bool {
523    let verifications = [
524        &revision_result.file_verification,
525        &revision_result.content_verification,
526        &revision_result.witness_verification,
527        &revision_result.signature_verification,
528        &revision_result.metadata_verification,
529    ];
530
531    for verification in verifications {
532        if matches!(verification.status, ResultStatusEnum::AVAILABLE) && !verification.successful {
533            return false;
534        }
535    }
536
537    true
538}
539
540/// Computes a witness hash from its components.
541/// 
542/// # Arguments
543/// * `domain_snapshot_genesis_hash` - The genesis hash of the domain snapshot
544/// * `merkle_root` - The root of the merkle tree
545/// * `witness_network` - The network identifier
546/// * `witness_event_transaction_hash` - The transaction hash of the witness event
547/// 
548/// # Returns
549/// `Hash` - The computed witness hash
550pub fn witness_hash(
551    domain_snapshot_genesis_hash: &Hash,
552    merkle_root: &Hash,
553    witness_network: &str,
554    witness_event_transaction_hash: &TxHash,
555) -> Hash {
556    // 2.a create hasher {w}
557    let mut w = crypt::Hasher::default();
558    // 2.b add rev.witness.domain_snapshot_genesis_hash to hasher {w}
559    w.update(domain_snapshot_genesis_hash.to_stackstr());
560    // 2.c add rev.witness.merkle_root to hasher {w}
561    w.update(merkle_root.to_stackstr());
562    // 2.d add rev.witness.witness_network to hasher {w}
563    w.update(witness_network);
564    // 2.e add rev.witness.witness_event_transaction_hash to hasher {w}
565    w.update(witness_event_transaction_hash.to_stackstr());
566    Hash::from(w.finalize())
567}
568
569/// Computes a signature hash from a signature and public key.
570/// 
571/// # Arguments
572/// * `signature` - The digital signature
573/// * `public_key` - The public key used for signing
574/// 
575/// # Returns
576/// `Hash` - The computed signature hash
577pub fn signature_hash(signature: &Signature, public_key: &PublicKey) -> Hash {
578    // 4.a create hasher {s}
579    let mut s = crypt::Hasher::default();
580    // 4.b add rev.signature.signature to hasher {s}
581    s.update(signature.to_stackstr());
582    // 4.c add rev.signature.public_key to hasher {s}
583    s.update(public_key.to_stackstr());
584    Hash::from(s.finalize())
585}
586
587/// Computes a content hash from a map of content data.
588/// 
589/// # Arguments
590/// * `content` - Map of content key-value pairs
591/// 
592/// # Returns
593/// `Hash` - The computed content hash
594pub fn content_hash(content: &BTreeMap<String, String>) -> Hash {
595    // 3.a create hasher {c}
596    let mut c = crypt::Hasher::default();
597    // 3.b iterate over rev.content.content by its keys
598    for value in content.values() {
599        // 3.c add each value of rev.content.content to hasher {c}
600        c.update(value);
601    }
602    Hash::from(c.finalize())
603}
604
605/// Computes a metadata hash from revision metadata components.
606/// 
607/// # Arguments
608/// * `domain_id` - The domain identifier
609/// * `time_stamp` - The timestamp of the revision
610/// * `previous_verification_hash` - Optional hash from previous verification
611/// 
612/// # Returns
613/// `Hash` - The computed metadata hash
614pub fn metadata_hash(
615    domain_id: &str,
616    time_stamp: &Timestamp,
617    previous_verification_hash: Option<&Hash>,
618) -> Hash {
619    // 4.a create hasher {m}
620    let mut m = crypt::Hasher::default();
621    // 4.b add rev.metadata.domain_id to hasher {m}
622    m.update(domain_id);
623    // 4.c add rev.metadata.time_stamp (in format %Y%m%d%H%M%S) to hasher {m}
624    m.update(time_stamp.to_string());
625    // 4.d if rev.metadata.previous_verification_hash exists then add rev.metadata.previous_verification_hash to hasher {m}
626    if let Some(prev_verification_hash) = previous_verification_hash {
627        m.update(prev_verification_hash.to_stackstr());
628    }
629    Hash::from(m.finalize())
630}
631
632/// Computes a verification hash from multiple component hashes.
633/// 
634/// # Arguments
635/// * `content_hash` - Hash of the content
636/// * `metadata_hash` - Hash of the metadata
637/// * `signature_hash` - Optional signature hash
638/// * `witness_hash` - Optional witness hash
639/// 
640/// # Returns
641/// `Hash` - The computed verification hash
642pub fn verification_hash(
643    content_hash: &Hash,
644    metadata_hash: &Hash,
645    signature_hash: Option<&Hash>,
646    witness_hash: Option<&Hash>,
647) -> Hash {
648
649    let mut v = crypt::Hasher::default();
650    // 5.b add rev.content.content_hash to hasher {v}
651    v.update(content_hash.to_stackstr());
652    // 5.c add rev.metadata.metadata_hash to hasher {v}
653    v.update(metadata_hash.to_stackstr());
654    // 5.d if prev?.signature exists then add prev.signature.signature_hash to hasher {v}
655    if let Some(prev_signature_hash) = signature_hash {
656        v.update(prev_signature_hash.to_stackstr());
657    }
658    // 5.e if prev?.witness exists then add prev.witness.witness_hash to hasher {v}
659    if let Some(prev_witness_hash) = witness_hash {
660        v.update(prev_witness_hash.to_stackstr());
661    }
662    Hash::from(v.finalize())
663}
664
665
666/// Validates page data revisions for integrity and chain consistency.
667/// 
668/// # Arguments
669/// * `revisions` - Vector of hash-revision pairs to validate
670/// 
671/// # Returns
672/// A tuple containing:
673/// * `bool` - Whether the revisions are valid
674/// * `String` - A status message describing the validation result
675pub fn check_if_page_data_revision_are_okay(revisions: Vec<(Hash, Revision)>) -> (bool, String) {
676    let mut is_valid = (true, "".to_string());
677    let has_valid_genessis = revsions_has_valid_genesis(revisions.clone());
678    // tracing::debug!("revsions_has_valid_genesis {:#?}", has_valid_genessis);
679
680    if has_valid_genessis.is_none() {
681        return (
682            false,
683            "revisions do not contain a valid genesis".to_string(),
684        );
685    }
686
687    // check if the revision > metadata > previous_verification_hash is among the hash in revsions par
688    // if more that one is none return false
689    // there is a broken revision chain
690    let mut all_hashes: Vec<Hash> = Vec::new();
691    revisions
692        .iter()
693        .for_each(|(hash, _revision)| all_hashes.push(hash.clone()));
694
695    let genesis_hash_str = format!("{:#?}", has_valid_genessis.unwrap());
696
697    for (_index, (current_hash, current_revision)) in revisions.iter().enumerate() {
698        let current_hash_str = format!("{:#?}", current_hash);
699
700        // check hash if match the newly generated one
701        let recomputed_content_hash = compute_content_hash(&current_revision.content);
702
703        match recomputed_content_hash {
704            Ok(data) => {
705                if data == *current_hash {
706                    // tracing::error!("hashes match the generetaed one continue ...");
707                } else {
708                    // tracing::error!("\n hashes do not match revision has {:#?} \n vs generated hash {:#?} \n",data,current_hash );
709                    is_valid = (false, format!("a hash is not valid : {:#?}", current_hash));
710
711                    break;
712                }
713            }
714            Err(_error) => {
715                // tracing::error!("an error occured {}", error);
716                is_valid = (false, "error generating a hash ".to_string());
717                break;
718            }
719        }
720        // let contnent_hash_str = format!("{:#?}", revision.content.content_hash);
721        // let data_str = format!("{:#?}", revision.content.content_hash);
722        // tracing::error!("returd conetnet is   {} \n  my json content hash is {} \n", data_str, contnent_hash_str);
723        // matches = data ==revision.content.content_hash  ;//revision.content.content_hash;
724
725        // chec if the hash chain is valid (ie if there any orphan revisions)
726        if current_hash_str == genesis_hash_str {
727            // tracing::debug!("ignoring genessis hash is {:#?}", genesis_hash_str);
728        } else {
729            let contains = all_hashes.contains(current_hash);
730
731            if contains == false {
732                // tracing::debug!("cannot find hash is {:#?}", current_hash_str);
733                is_valid = (false, "Hash chain is invalid ".to_string());
734                break;
735            }
736        }
737    }
738
739    return is_valid;
740}
741
742
743/// Checks if revisions contain a valid genesis block.
744/// 
745/// # Arguments
746/// * `revisions` - Vector of hash-revision pairs to check
747/// 
748/// # Returns
749/// `Option<Hash>` - The genesis hash if found and valid, None otherwise
750pub fn revsions_has_valid_genesis(revisions: Vec<(Hash, Revision)>) -> Option<Hash> {
751    // let mut is_valid= true;
752
753    if revisions.len() <= 1 {
754        // tracing::debug!("The lengthe is equal to or ess than 1 {}", revisions.len());
755        return None;
756    }
757
758    let mut revision_genesis: Vec<&Revision> = Vec::new();
759
760    for (_index, (_hash, revision)) in revisions.iter().enumerate() {
761        match revision.metadata.previous_verification_hash {
762            Some(_data) => {
763                // tracing::debug!("The previous hash is {:#?}", data);
764            }
765            None => {
766                // tracing::debug!("pushing revision to vector {:#?}", revision);
767                revision_genesis.push(revision)
768            }
769        }
770    }
771
772    if revision_genesis.len() > 1 {
773        // tracing::debug!(
774        //     "The genesis revision  length {} are {:#?}",
775        //     revision_genesis.len(),
776        //     revision_genesis
777        // );
778        return None;
779    }
780
781    let res = revision_genesis.first();
782    if res.is_none() {
783        // tracing::debug!("No genesis hash  (vec is empty)",);
784        return None;
785    }
786
787    // tracing::debug!("************************ {:#?}", res);
788    // we use unwrapp becasue we are guaranteed the res has value due to the if check above
789    return Some(res.unwrap().metadata.verification_hash);
790}
791
792/// Computes a content hash from revision content.
793/// 
794/// # Arguments
795/// * `content_par` - The revision content containing file data
796/// 
797/// # Returns
798/// `Result<Hash, String>` - The computed hash or an error message
799pub fn compute_content_hash(content_par: &RevisionContent) -> Result<Hash, String> {
800    let b64 = content_par.file.clone().unwrap().data;
801
802    let mut file_hasher = sha3::Sha3_512::default();
803    file_hasher.update(b64.clone());
804    let file_hash_current = Hash::from(file_hasher.finalize());
805
806    let mut content_current = BTreeMap::new();
807
808    content_current.insert("file_hash".to_owned(), file_hash_current.to_string());
809
810    // println!("{:#?}", content_current);
811    // tracing::debug!("{:#?}", content_current);
812
813    let content_hash_current = content_hash(&content_current.clone());
814
815    // tracing::debug!("{:#?}", content_hash_current);
816
817    Ok(content_hash_current)
818}
819
820
821/// Creates an empty hash using SHA3-512.
822/// 
823/// # Returns
824/// `Hash` - A hash computed from an empty string
825pub fn make_empty_hash() -> Hash {
826    let mut hasher = sha3::Sha3_512::default();
827    hasher.update("");
828    let empty_hash = Hash::from(hasher.finalize());
829    empty_hash
830}