1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Root reconstruction from an inclusion path — RFC 6962 §2.1.1.
//!
//! [`verify_inclusion`](super::verify_inclusion) answers "does this proof hold
//! against a root I already have?". This module answers the different question
//! a receipt verifier must ask: **"what root does this proof imply?"**
//!
//! The distinction is the whole reason receipts can carry their inclusion proof
//! in an *unprotected* COSE header. An anchor signs the root as a detached
//! payload; the verifier recomputes a candidate root from the leaf and the path
//! and verifies the signature against *that*. A tampered path therefore yields
//! a root the anchor never signed, and the signature fails — the proof is
//! authenticated by consequence rather than by coverage. Nothing here is
//! trusted: this function's output is an input to a signature check, never a
//! verdict.
//!
//! It also means a receipt is self-verifying. A stranger holding the receipt
//! and the leaf needs nothing else — no checkpoint, no published root, no
//! service to ask. Had the root been supplied by the caller instead, the
//! receipt would only be checkable alongside a separate artifact.
//!
//! # Why this is written out rather than delegated
//!
//! `ct-merkle` verifies a proof against a supplied root and exposes no
//! root-reconstruction entry point, so the RFC 6962 walk is implemented here.
//! That creates one risk worth naming: a walk that disagreed with ct-merkle's
//! tree shape would produce roots no anchor ever signed, and *every receipt
//! ever issued* would be unverifiable. The risk is closed by test rather than
//! by care — `reconstruct_tests` builds real trees at every size from 1 to 33
//! and reconstructs from every leaf index in each, requiring the result to
//! equal the tree's own root. Any future change to ct-merkle's shape fails
//! loudly there instead of silently invalidating receipts.
use ;
use crate;
/// RFC 6962 domain-separation prefix for interior nodes.
const NODE_PREFIX: u8 = 0x01;
/// Length of a SHA-256 digest, and so of every node in an inclusion path.
const DIGEST_LEN: usize = 32;
/// Reconstructs the Merkle Tree Hash implied by an inclusion path.
///
/// Walks `path` upward from `leaf_hash` per RFC 6962 §2.1.1, combining nodes as
/// `SHA-256(0x01 ‖ left ‖ right)`, and returns the root the path implies for a
/// tree of `tree_size` leaves with the leaf at `leaf_index`.
///
/// `leaf_hash` is the RFC 6962 leaf hash — `SHA-256(0x00 ‖ leaf-bytes)` for raw
/// leaves, which [`raw_leaf_hash`](super::raw_leaf_hash) computes.
///
/// The returned root is **not** a verification result. It is a value to be
/// checked against something independently trustworthy — an anchor's signature
/// over it, or a published checkpoint. Treating a successful reconstruction as
/// proof of inclusion would be exactly the silent success this crate exists to
/// prevent: every well-formed path reconstructs *some* root.
///
/// # Errors
///
/// Returns [`TrustError::MerkleTree`] if `tree_size` is zero, `leaf_index` is
/// not below `tree_size`, `path` is not a whole number of 32-byte digests, or
/// the path length disagrees with the one `(leaf_index, tree_size)` requires —
/// too short and too long are both rejected, since a path of the wrong length
/// for the claimed tree describes a different tree.
/// Hashes an interior node as RFC 6962's `SHA-256(0x01 ‖ left ‖ right)`.