penumbra_sdk_tct/internal/hash/
option.rs

1use ark_ff::{BigInt, PrimeField};
2use decaf377::Fq;
3use std::fmt::Debug;
4
5use crate::prelude::*;
6
7/// A representation of `Option<Hash>` without the tag bytes required by `Option`, because we
8/// know that no valid [`struct@Hash`] will be equal to `[u64::MAX; 4]`, since the modulus for
9/// [`Commitment`](crate::Commitment) is too small.
10///
11/// This type is inter-convertible via [`From`] and [`Into`] with `Option<Hash>`, and that is
12/// its only purpose.
13#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(from = "Option<Hash>", into = "Option<Hash>")]
15pub struct OptionHash {
16    inner: [u64; 4],
17}
18
19impl Debug for OptionHash {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        <Option<Hash>>::from(*self).fmt(f)
22    }
23}
24
25impl Default for OptionHash {
26    fn default() -> Self {
27        Self {
28            inner: [u64::MAX; 4],
29        }
30    }
31}
32
33impl From<Option<Hash>> for OptionHash {
34    fn from(hash: Option<Hash>) -> Self {
35        match hash {
36            Some(hash) => Self {
37                inner: Fq::into_bigint(hash.0).0,
38            },
39            None => Self {
40                // This sentinel value is not a valid `Fq` because it's bigger than the modulus,
41                // which means that it will never occur otherwise
42                inner: [u64::MAX; 4],
43            },
44        }
45    }
46}
47
48impl From<OptionHash> for Option<Hash> {
49    fn from(hash: OptionHash) -> Self {
50        if hash.inner == [u64::MAX; 4] {
51            None
52        } else {
53            // We're directly constructing the hash here by coercing the bytes into the right type,
54            // but this is safe because we know that the bytes are a real `Fq` and not the sentinel
55            // value we just checked for
56            Some(Hash::new(
57                Fq::from_bigint(BigInt::new(hash.inner))
58                    .expect("convert bytes to a valid Fq element"),
59            ))
60        }
61    }
62}