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
139
//! Deterministic serialization of arbitrary `Serialize` leaves into bytes the
//! Merkle tree can hash.
//!
//! ct-merkle's `MemoryBackedTree` requires leaves to implement
//! `ct_merkle::HashableLeaf`. A blanket impl is provided for any
//! `T: AsRef<[u8]>`, so `SerializedLeaf` satisfies the bound by exposing
//! its bytes through [`AsRef`]. The tree never sees the original `L` —
//! `serialize_leaf` is the single conversion point for `Serialize` leaves,
//! and `SerializedLeaf::from_raw_bytes` is the single entry point for the
//! raw-leaf path (see below).
//!
//! Serialization is performed with `postcard`, a compact and deterministic
//! binary format. Two consumers serializing the same value with the same
//! schema therefore produce byte-identical input to the hash function, which
//! is what makes [`AppendOnlyTree::root`] stable across runs.
//!
//! # The postcard encoding is a FROZEN WIRE CONTRACT
//!
//! Postcard is a non-self-describing format: it writes no field names, no
//! tags, and no schema information. The encoded bytes are determined
//! entirely by the leaf type's **shape** — its fields, their declaration
//! order, and (for enums) the declaration order of variants. Consequently,
//! once leaves of a type have been hashed into a persisted or published
//! tree, that type's shape is frozen forever:
//!
//! - **Never** add, remove, rename-with-retype, or reorder fields.
//! - **Never** reorder, insert, or remove enum variants.
//! - **Never** change a field's type, even to a layout-compatible one.
//!
//! Any such change silently changes the serialized bytes of historical
//! leaf values. There is no error and no version mismatch — every
//! previously published root and proof simply stops verifying, which for a
//! transparency log is indistinguishable from tampering. Schema evolution
//! requires a **new versioned leaf type** or an **explicitly versioned
//! envelope**; it must never be done by editing an existing leaf type in
//! place.
//!
//! Consumers who need long-lived verifiability are strongly encouraged to
//! pin leaves as pre-encoded byte payloads — e.g. a leaf struct holding a
//! `Vec<u8>` the consumer encodes and versions itself — so the bytes that
//! enter the tree are under the consumer's explicit control rather than
//! derived from a Rust type's shape.
//!
//! # The raw-leaf path (transparency-log invariant)
//!
//! `postcard` prefixes byte-sequence leaves with a length varint, so the
//! bytes a `Serialize` tree hashes are **not** the consumer's bytes — a
//! third party holding only the raw leaf cannot recompute the leaf hash
//! with standard tooling. `SerializedLeaf::from_raw_bytes` wraps bytes
//! verbatim (no postcard, no length prefix), so a tree fed through it
//! hashes exactly `SHA-256(0x00 ‖ bytes)` per RFC 6962. **Invariant:** for
//! every raw leaf, `leaf_hash = SHA-256(0x00 ‖ leaf-bytes)`; reproduce with
//! `(printf '\x00'; cat leaf-file) | shasum -a 256`. The postcard contract
//! above is untouched — the two paths never mix in one tree (see
//! [`RawLeaf`](super::tree::RawLeaf)).
//!
//! Failures (e.g. a `Serialize` impl that returns an error) are mapped to
//! [`TrustError::MerkleTree`], not panics.
//!
//! [`AppendOnlyTree::root`]: super::tree::AppendOnlyTree::root
//! [`TrustError::MerkleTree`]: crate::error::TrustError::MerkleTree
use Serialize;
use ;
use crate;
/// Byte representation of a Merkle leaf.
///
/// Implements [`AsRef<[u8]>`] so that ct-merkle's blanket
/// `impl<T: AsRef<[u8]>> HashableLeaf for T` applies and the tree can hash
/// the wrapped bytes directly. The inner buffer is intentionally private:
/// callers outside this module work in terms of the original `L` and the
/// [`serialize_leaf`] helper.
pub ;
/// Serializes a leaf into the canonical byte representation used by the
/// Merkle tree.
///
/// The postcard encoding of `L` is a **frozen wire contract** (see the
/// module docs): the bytes produced here depend on `L`'s fields, field
/// order, and enum variant order, and those must never change once leaves
/// of `L` are part of a persisted or published tree. Evolving the schema
/// means introducing a new versioned leaf type, not editing `L`.
///
/// # Errors
///
/// Returns [`TrustError::MerkleTree`] if `postcard` rejects the value — for
/// example, a custom `Serialize` impl that fails or a type postcard cannot
/// represent (such as a non-`'static` map with non-string keys when a schema
/// constraint is violated).
pub
/// RFC 6962 leaf hash of raw bytes: `SHA-256(0x00 ‖ leaf_bytes)`.
///
/// Public so consumers (and the CLI) can display and compare leaf hashes
/// without a tree. **Invariant:** this is exactly the hash the raw-leaf
/// tree ([`RawLeaf`](super::tree::RawLeaf)) computes for a leaf, and it is
/// reproducible by any stranger with standard tooling:
/// `(printf '\x00'; cat leaf-file) | shasum -a 256`.