Skip to main content

p3_symmetric/
hash.rs

1use alloc::vec;
2use alloc::vec::{IntoIter, Vec};
3use core::borrow::Borrow;
4use core::marker::PhantomData;
5
6use p3_util::log2_strict_usize;
7use serde::de::Error;
8use serde::{Deserialize, Deserializer, Serialize};
9
10/// A wrapper around an array digest, with a phantom type parameter to ensure that the digest is
11/// associated with a particular field.
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(bound(serialize = "[W; DIGEST_ELEMS]: Serialize"))]
14#[serde(bound(deserialize = "[W; DIGEST_ELEMS]: Deserialize<'de>"))]
15pub struct Hash<F, W, const DIGEST_ELEMS: usize> {
16    value: [W; DIGEST_ELEMS],
17    _marker: PhantomData<F>,
18}
19
20/// The Merkle cap of height `h` of a Merkle tree is the `h`-th layer (from the root) of the tree.
21/// It can be used in place of the root to verify Merkle paths, which are `h` elements shorter.
22///
23/// A cap of height 0 contains a single element (the root), while a cap of height `h` contains
24/// `2^h` elements. The `Digest` type is the full digest (e.g. `[W; DIGEST_ELEMS]`).
25///
26/// The root count is always a power of two.
27///
28/// A cap is one full layer of a binary tree, so a layer at depth `h` holds `2^h` digests.
29///
30/// The height is recovered as `log_2` of the root count, which exists only for a power of two.
31///
32/// Every path that builds a cap enforces this, including the one that reads it off the wire.
33#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
34#[serde(bound(serialize = "Digest: Serialize"))]
35pub struct MerkleCap<F, Digest> {
36    cap: Vec<Digest>,
37    _marker: PhantomData<F>,
38}
39
40/// Mirror of the cap layer that lets the derive produce the decoder.
41///
42/// The cap itself exposes no unchecked constructor, so the derive cannot target it.
43///
44/// Field names, field order and the container name reproduce the derived encoding exactly.
45///
46/// Changing any of the three moves the bytes of every stored proof.
47#[derive(Deserialize)]
48#[serde(rename = "MerkleCap")]
49#[serde(bound(deserialize = "Digest: Deserialize<'de>"))]
50struct MerkleCapRepr<F, Digest> {
51    /// The digests of the layer, left to right.
52    cap: Vec<Digest>,
53    /// Pins the layer to one field without carrying any data of its own.
54    _marker: PhantomData<F>,
55}
56
57impl<'de, F, Digest: Deserialize<'de>> Deserialize<'de> for MerkleCap<F, Digest> {
58    /// # Errors
59    ///
60    /// Returns an error when the root count is not a power of two.
61    ///
62    /// Such a count has no base-two logarithm, so the cap would have no height.
63    ///
64    /// Untrusted bytes are the only route by which such a cap could reach a verifier.
65    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
66        // Read the wire shape first, so the check runs on a fully decoded layer.
67        let MerkleCapRepr { cap, _marker } = MerkleCapRepr::<F, Digest>::deserialize(deserializer)?;
68
69        // Invariant: a cap is a full tree layer, so it holds 2^h digests for its depth h.
70        //
71        //     4 roots -> depth 2, accepted
72        //     3 roots -> no layer has that size, rejected
73        //     0 roots -> no layer has that size, rejected
74        if !cap.len().is_power_of_two() {
75            return Err(D::Error::invalid_length(
76                cap.len(),
77                &"a power-of-two number of Merkle cap roots",
78            ));
79        }
80
81        Ok(Self { cap, _marker })
82    }
83}
84
85impl<F, Digest> MerkleCap<F, Digest> {
86    /// Wrap one full layer of digests as a cap.
87    ///
88    /// # Panics
89    ///
90    /// Panics when the number of digests is not a power of two.
91    pub fn new(cap: Vec<Digest>) -> Self {
92        // Invariant: a cap is a full tree layer, so it holds 2^h digests for its depth h.
93        assert!(
94            cap.len().is_power_of_two(),
95            "a Merkle cap holds a power-of-two number of roots, got {}",
96            cap.len()
97        );
98        Self {
99            cap,
100            _marker: PhantomData,
101        }
102    }
103
104    /// Returns the number of digests in the cap.
105    #[must_use]
106    pub const fn num_roots(&self) -> usize {
107        self.cap.len()
108    }
109
110    /// Returns the height of the cap (log2 of the number of elements).
111    /// A cap with 1 element has height 0, a cap with 2 elements has height 1, etc.
112    #[must_use]
113    pub const fn height(&self) -> usize {
114        log2_strict_usize(self.num_roots())
115    }
116
117    /// Returns a reference to the underlying slice of digests.
118    #[must_use]
119    pub fn roots(&self) -> &[Digest] {
120        &self.cap
121    }
122
123    /// Flattens the cap into a single vector of digest words.
124    pub fn into_roots(self) -> Vec<Digest> {
125        self.cap.into_iter().collect()
126    }
127}
128
129impl<F, Digest> From<Vec<Digest>> for MerkleCap<F, Digest> {
130    fn from(cap: Vec<Digest>) -> Self {
131        Self::new(cap)
132    }
133}
134
135impl<F, W, const N: usize> From<Hash<F, W, N>> for MerkleCap<F, [W; N]> {
136    fn from(hash: Hash<F, W, N>) -> Self {
137        Self::new(vec![hash.into()])
138    }
139}
140
141impl<F, Digest> Borrow<[Digest]> for MerkleCap<F, Digest> {
142    fn borrow(&self) -> &[Digest] {
143        &self.cap
144    }
145}
146
147impl<F, Digest> AsRef<[Digest]> for MerkleCap<F, Digest> {
148    fn as_ref(&self) -> &[Digest] {
149        &self.cap
150    }
151}
152
153impl<F, Digest> core::ops::Index<usize> for MerkleCap<F, Digest> {
154    type Output = Digest;
155
156    fn index(&self, index: usize) -> &Self::Output {
157        &self.cap[index]
158    }
159}
160
161impl<F, Digest> IntoIterator for MerkleCap<F, Digest> {
162    type Item = Digest;
163    type IntoIter = IntoIter<Digest>;
164
165    fn into_iter(self) -> Self::IntoIter {
166        self.cap.into_iter()
167    }
168}
169
170impl<F, W, const DIGEST_ELEMS: usize> From<[W; DIGEST_ELEMS]> for Hash<F, W, DIGEST_ELEMS> {
171    fn from(value: [W; DIGEST_ELEMS]) -> Self {
172        Self {
173            value,
174            _marker: PhantomData,
175        }
176    }
177}
178
179impl<F, W, const DIGEST_ELEMS: usize> From<Hash<F, W, DIGEST_ELEMS>> for [W; DIGEST_ELEMS] {
180    fn from(value: Hash<F, W, DIGEST_ELEMS>) -> [W; DIGEST_ELEMS] {
181        value.value
182    }
183}
184
185impl<F, W: PartialEq, const DIGEST_ELEMS: usize> PartialEq<[W; DIGEST_ELEMS]>
186    for Hash<F, W, DIGEST_ELEMS>
187{
188    fn eq(&self, other: &[W; DIGEST_ELEMS]) -> bool {
189        self.value == *other
190    }
191}
192
193impl<F, W, const DIGEST_ELEMS: usize> IntoIterator for Hash<F, W, DIGEST_ELEMS> {
194    type Item = W;
195    type IntoIter = core::array::IntoIter<W, DIGEST_ELEMS>;
196
197    fn into_iter(self) -> Self::IntoIter {
198        self.value.into_iter()
199    }
200}
201
202impl<F, W, const DIGEST_ELEMS: usize> Borrow<[W; DIGEST_ELEMS]> for Hash<F, W, DIGEST_ELEMS> {
203    fn borrow(&self) -> &[W; DIGEST_ELEMS] {
204        &self.value
205    }
206}
207
208impl<F, W, const DIGEST_ELEMS: usize> AsRef<[W; DIGEST_ELEMS]> for Hash<F, W, DIGEST_ELEMS> {
209    fn as_ref(&self) -> &[W; DIGEST_ELEMS] {
210        &self.value
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use alloc::string::ToString;
217    use alloc::vec;
218
219    use p3_goldilocks::Goldilocks;
220
221    use super::*;
222
223    type F = Goldilocks;
224    type Digest = [u8; 4];
225
226    #[test]
227    fn test_merkle_cap_new_with_power_of_two_sizes() {
228        let cap = MerkleCap::<F, Digest>::new(vec![[7u8; 4]]);
229        assert_eq!(cap.num_roots(), 1);
230        assert_eq!(cap.height(), 0);
231
232        let cap = MerkleCap::<F, Digest>::new(vec![[0u8; 4]; 2]);
233        assert_eq!(cap.num_roots(), 2);
234        assert_eq!(cap.height(), 1);
235
236        let cap = MerkleCap::<F, Digest>::new(vec![[0u8; 4]; 8]);
237        assert_eq!(cap.num_roots(), 8);
238        assert_eq!(cap.height(), 3);
239    }
240
241    #[test]
242    fn test_merkle_cap_wire_shape_is_stable() {
243        // Fixture state: four roots, each a digest of four repeated bytes.
244        let cap = MerkleCap::<F, Digest>::new(vec![[1u8; 4], [2u8; 4], [3u8; 4], [4u8; 4]]);
245
246        // Compact encoding: a varint root count, the roots in order, nothing for the marker.
247        //
248        //     04 | 01010101 | 02020202 | 03030303 | 04040404
249        //
250        // Every stored proof replays these bytes, so they are pinned rather than round-tripped.
251        let bytes = postcard::to_allocvec(&cap).unwrap();
252        assert_eq!(bytes, [4, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]);
253        let back: MerkleCap<F, Digest> = postcard::from_bytes(&bytes).unwrap();
254        assert_eq!(back, cap);
255        assert_eq!(back.height(), 2);
256
257        // Self-describing encoding: a map whose two keys pin the field names and their order.
258        let json = serde_json::to_string(&cap).unwrap();
259        assert_eq!(
260            json,
261            r#"{"cap":[[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4]],"_marker":null}"#
262        );
263        assert_eq!(
264            serde_json::from_str::<MerkleCap<F, Digest>>(&json).unwrap(),
265            cap
266        );
267    }
268
269    #[test]
270    fn test_merkle_cap_deserialize_rejects_non_power_of_two_root_count() {
271        // Three roots is the smallest count no tree layer can have.
272        //
273        // Zero roots is the degenerate count a truncating encoder would produce.
274        //
275        // The self-describing decoder reports the count and the requirement verbatim.
276        //
277        // Pinning the whole message keeps the count in it and keeps it readable to an operator.
278        for (json, message) in [
279            (
280                r#"{"cap":[[1,1,1,1],[2,2,2,2],[3,3,3,3]],"_marker":null}"#,
281                "invalid length 3, expected a power-of-two number of Merkle cap roots",
282            ),
283            (
284                r#"{"cap":[],"_marker":null}"#,
285                "invalid length 0, expected a power-of-two number of Merkle cap roots",
286            ),
287        ] {
288            let err = serde_json::from_str::<MerkleCap<F, Digest>>(json)
289                .expect_err("a cap with a non-power-of-two root count must not deserialize");
290            assert_eq!(err.to_string(), message);
291        }
292    }
293
294    #[test]
295    fn test_merkle_cap_compact_decoding_rejects_a_non_power_of_two_root_count() {
296        // The compact decoder collapses every failure into one opaque message.
297        //
298        // Asserting that text would pin a catch-all that a truncated buffer also produces.
299        //
300        // Instead each rejected count is paired with the next legal one:
301        //
302        //     03 | three roots  -> refused
303        //     04 | four roots   -> accepted
304        //
305        // Only the count differs between the two, so the count is what the refusal turns on.
306        for (rejected, accepted, roots) in [
307            (
308                &[3u8, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3][..],
309                &[4u8, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4][..],
310                4,
311            ),
312            (&[0u8][..], &[1u8, 1, 1, 1, 1][..], 1),
313        ] {
314            postcard::from_bytes::<MerkleCap<F, Digest>>(rejected)
315                .expect_err("a cap with a non-power-of-two root count must not deserialize");
316
317            let cap = postcard::from_bytes::<MerkleCap<F, Digest>>(accepted)
318                .expect("a power-of-two root count is accepted");
319            assert_eq!(cap.num_roots(), roots);
320        }
321    }
322
323    #[test]
324    #[should_panic]
325    fn test_merkle_cap_new_panics_on_empty() {
326        let _ = MerkleCap::<F, Digest>::new(vec![]);
327    }
328
329    #[test]
330    #[should_panic]
331    fn test_merkle_cap_new_panics_on_three() {
332        let _ = MerkleCap::<F, Digest>::new(vec![[0u8; 4]; 3]);
333    }
334
335    #[test]
336    #[should_panic]
337    fn test_merkle_cap_from_vec_panics_on_empty() {
338        let _: MerkleCap<F, Digest> = vec![].into();
339    }
340
341    #[test]
342    fn test_merkle_cap_from_hash() {
343        let hash = Hash::<F, u8, 4>::from([1u8, 2, 3, 4]);
344        let cap: MerkleCap<F, [u8; 4]> = hash.into();
345        assert_eq!(cap.num_roots(), 1);
346        assert_eq!(cap.height(), 0);
347    }
348}