Skip to main content

auths_transparency/
proof.rs

1use serde::{Deserialize, Serialize};
2
3use crate::types::MerkleHash;
4
5/// Merkle inclusion proof for a single entry in the log.
6///
7/// Proves that a leaf at `index` is included in the tree of `size` leaves
8/// with the given `root`.
9///
10/// Args:
11/// * `index` — Zero-based leaf index.
12/// * `size` — Tree size (number of leaves) when the proof was generated.
13/// * `root` — Merkle root at tree size `size`.
14/// * `hashes` — Sibling hashes from leaf to root.
15///
16/// Usage:
17/// ```ignore
18/// let proof = InclusionProof { index: 5, size: 16, root, hashes: vec![...] };
19/// proof.verify(&leaf_hash)?;
20/// ```
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
22#[allow(missing_docs)]
23pub struct InclusionProof {
24    pub index: u64,
25    pub size: u64,
26    pub root: MerkleHash,
27    pub hashes: Vec<MerkleHash>,
28}
29
30impl InclusionProof {
31    /// Verify that `leaf_hash` is included in the tree.
32    pub fn verify(&self, leaf_hash: &MerkleHash) -> Result<(), crate::error::TransparencyError> {
33        crate::merkle::verify_inclusion(leaf_hash, self.index, self.size, &self.hashes, &self.root)
34    }
35}
36
37/// Merkle consistency proof between two tree sizes.
38///
39/// Proves that the tree at `old_size` is a prefix of the tree at `new_size`.
40///
41/// Args:
42/// * `old_size` — Earlier tree size.
43/// * `new_size` — Later tree size.
44/// * `old_root` — Root at `old_size`.
45/// * `new_root` — Root at `new_size`.
46/// * `hashes` — Consistency proof hashes.
47///
48/// Usage:
49/// ```ignore
50/// let proof = ConsistencyProof { old_size: 8, new_size: 16, .. };
51/// proof.verify()?;
52/// ```
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
54#[allow(missing_docs)]
55pub struct ConsistencyProof {
56    pub old_size: u64,
57    pub new_size: u64,
58    pub old_root: MerkleHash,
59    pub new_root: MerkleHash,
60    pub hashes: Vec<MerkleHash>,
61}
62
63impl ConsistencyProof {
64    /// Verify that the old tree is a prefix of the new tree.
65    pub fn verify(&self) -> Result<(), crate::error::TransparencyError> {
66        crate::merkle::verify_consistency(
67            self.old_size,
68            self.new_size,
69            &self.hashes,
70            &self.old_root,
71            &self.new_root,
72        )
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79    use crate::merkle::{hash_children, hash_leaf};
80
81    #[test]
82    fn inclusion_proof_verify() {
83        let a = hash_leaf(b"a");
84        let b = hash_leaf(b"b");
85        let root = hash_children(&a, &b);
86
87        let proof = InclusionProof {
88            index: 0,
89            size: 2,
90            root,
91            hashes: vec![b],
92        };
93        proof.verify(&a).unwrap();
94    }
95
96    #[test]
97    fn inclusion_proof_json_roundtrip() {
98        let proof = InclusionProof {
99            index: 3,
100            size: 8,
101            root: MerkleHash::from_bytes([0xaa; 32]),
102            hashes: vec![
103                MerkleHash::from_bytes([0xbb; 32]),
104                MerkleHash::from_bytes([0xcc; 32]),
105            ],
106        };
107        let json = serde_json::to_string(&proof).unwrap();
108        let back: InclusionProof = serde_json::from_str(&json).unwrap();
109        assert_eq!(proof, back);
110    }
111
112    #[test]
113    fn consistency_proof_json_roundtrip() {
114        let proof = ConsistencyProof {
115            old_size: 4,
116            new_size: 8,
117            old_root: MerkleHash::from_bytes([0x11; 32]),
118            new_root: MerkleHash::from_bytes([0x22; 32]),
119            hashes: vec![MerkleHash::from_bytes([0x33; 32])],
120        };
121        let json = serde_json::to_string(&proof).unwrap();
122        let back: ConsistencyProof = serde_json::from_str(&json).unwrap();
123        assert_eq!(proof, back);
124    }
125}