subspace_core_primitives/
pot.rs

1//! Proof of time-related data structures.
2
3use crate::Randomness;
4use crate::hashes::{Blake3Hash, blake3_hash, blake3_hash_list};
5use core::num::NonZeroU8;
6use core::str::FromStr;
7use core::{fmt, mem};
8use derive_more::{AsMut, AsRef, Deref, DerefMut, From};
9use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
10use scale_info::TypeInfo;
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13#[cfg(feature = "serde")]
14use serde::{Deserializer, Serializer};
15
16/// Proof of time key(input to the encryption).
17#[derive(
18    Default,
19    Copy,
20    Clone,
21    Eq,
22    PartialEq,
23    From,
24    AsRef,
25    AsMut,
26    Deref,
27    DerefMut,
28    Encode,
29    Decode,
30    TypeInfo,
31    MaxEncodedLen,
32)]
33pub struct PotKey([u8; Self::SIZE]);
34
35impl fmt::Debug for PotKey {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(f, "{}", hex::encode(self.0))
38    }
39}
40
41#[cfg(feature = "serde")]
42#[derive(Serialize, Deserialize)]
43#[serde(transparent)]
44struct PotKeyBinary([u8; PotKey::SIZE]);
45
46#[cfg(feature = "serde")]
47#[derive(Serialize, Deserialize)]
48#[serde(transparent)]
49struct PotKeyHex(#[serde(with = "hex")] [u8; PotKey::SIZE]);
50
51#[cfg(feature = "serde")]
52impl Serialize for PotKey {
53    #[inline]
54    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
55    where
56        S: Serializer,
57    {
58        if serializer.is_human_readable() {
59            PotKeyHex(self.0).serialize(serializer)
60        } else {
61            PotKeyBinary(self.0).serialize(serializer)
62        }
63    }
64}
65
66#[cfg(feature = "serde")]
67impl<'de> Deserialize<'de> for PotKey {
68    #[inline]
69    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
70    where
71        D: Deserializer<'de>,
72    {
73        Ok(Self(if deserializer.is_human_readable() {
74            PotKeyHex::deserialize(deserializer)?.0
75        } else {
76            PotKeyBinary::deserialize(deserializer)?.0
77        }))
78    }
79}
80
81impl fmt::Display for PotKey {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        write!(f, "{}", hex::encode(self.0))
84    }
85}
86
87impl FromStr for PotKey {
88    type Err = hex::FromHexError;
89
90    #[inline]
91    fn from_str(s: &str) -> Result<Self, Self::Err> {
92        let mut key = Self::default();
93        hex::decode_to_slice(s, key.as_mut())?;
94
95        Ok(key)
96    }
97}
98
99impl PotKey {
100    /// Size of proof of time key in bytes
101    pub const SIZE: usize = 16;
102}
103
104/// Proof of time seed
105#[derive(
106    Default,
107    Copy,
108    Clone,
109    Eq,
110    PartialEq,
111    Hash,
112    From,
113    AsRef,
114    AsMut,
115    Deref,
116    DerefMut,
117    Encode,
118    Decode,
119    TypeInfo,
120    MaxEncodedLen,
121)]
122pub struct PotSeed([u8; Self::SIZE]);
123
124impl fmt::Debug for PotSeed {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        write!(f, "{}", hex::encode(self.0))
127    }
128}
129
130#[cfg(feature = "serde")]
131#[derive(Serialize, Deserialize)]
132#[serde(transparent)]
133struct PotSeedBinary([u8; PotSeed::SIZE]);
134
135#[cfg(feature = "serde")]
136#[derive(Serialize, Deserialize)]
137#[serde(transparent)]
138struct PotSeedHex(#[serde(with = "hex")] [u8; PotSeed::SIZE]);
139
140#[cfg(feature = "serde")]
141impl Serialize for PotSeed {
142    #[inline]
143    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
144    where
145        S: Serializer,
146    {
147        if serializer.is_human_readable() {
148            PotSeedHex(self.0).serialize(serializer)
149        } else {
150            PotSeedBinary(self.0).serialize(serializer)
151        }
152    }
153}
154
155#[cfg(feature = "serde")]
156impl<'de> Deserialize<'de> for PotSeed {
157    #[inline]
158    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
159    where
160        D: Deserializer<'de>,
161    {
162        Ok(Self(if deserializer.is_human_readable() {
163            PotSeedHex::deserialize(deserializer)?.0
164        } else {
165            PotSeedBinary::deserialize(deserializer)?.0
166        }))
167    }
168}
169
170impl fmt::Display for PotSeed {
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        write!(f, "{}", hex::encode(self.0))
173    }
174}
175
176impl PotSeed {
177    /// Size of proof of time seed in bytes
178    pub const SIZE: usize = 16;
179
180    /// Derive initial PoT seed from genesis block hash
181    #[inline]
182    pub fn from_genesis(genesis_block_hash: &[u8], external_entropy: &[u8]) -> Self {
183        let hash = blake3_hash_list(&[genesis_block_hash, external_entropy]);
184        let mut seed = Self::default();
185        seed.copy_from_slice(&hash[..Self::SIZE]);
186        seed
187    }
188
189    /// Derive key from proof of time seed
190    #[inline]
191    pub fn key(&self) -> PotKey {
192        let mut key = PotKey::default();
193        key.copy_from_slice(&blake3_hash(&self.0)[..Self::SIZE]);
194        key
195    }
196}
197
198/// Proof of time output, can be intermediate checkpoint or final slot output
199#[derive(
200    Default,
201    Copy,
202    Clone,
203    Eq,
204    PartialEq,
205    Hash,
206    From,
207    AsRef,
208    AsMut,
209    Deref,
210    DerefMut,
211    Encode,
212    Decode,
213    TypeInfo,
214    MaxEncodedLen,
215)]
216#[repr(C)]
217pub struct PotOutput([u8; Self::SIZE]);
218
219impl fmt::Debug for PotOutput {
220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        write!(f, "{}", hex::encode(self.0))
222    }
223}
224
225#[cfg(feature = "serde")]
226#[derive(Serialize, Deserialize)]
227#[serde(transparent)]
228struct PotOutputBinary([u8; PotOutput::SIZE]);
229
230#[cfg(feature = "serde")]
231#[derive(Serialize, Deserialize)]
232#[serde(transparent)]
233struct PotOutputHex(#[serde(with = "hex")] [u8; PotOutput::SIZE]);
234
235#[cfg(feature = "serde")]
236impl Serialize for PotOutput {
237    #[inline]
238    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
239    where
240        S: Serializer,
241    {
242        if serializer.is_human_readable() {
243            PotOutputHex(self.0).serialize(serializer)
244        } else {
245            PotOutputBinary(self.0).serialize(serializer)
246        }
247    }
248}
249
250#[cfg(feature = "serde")]
251impl<'de> Deserialize<'de> for PotOutput {
252    #[inline]
253    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
254    where
255        D: Deserializer<'de>,
256    {
257        Ok(Self(if deserializer.is_human_readable() {
258            PotOutputHex::deserialize(deserializer)?.0
259        } else {
260            PotOutputBinary::deserialize(deserializer)?.0
261        }))
262    }
263}
264
265impl fmt::Display for PotOutput {
266    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267        write!(f, "{}", hex::encode(self.0))
268    }
269}
270
271impl PotOutput {
272    /// Size of proof of time proof in bytes
273    pub const SIZE: usize = 16;
274
275    /// Derives the global randomness from the output
276    #[inline]
277    pub fn derive_global_randomness(&self) -> Randomness {
278        Randomness::from(*blake3_hash(&self.0))
279    }
280
281    /// Derive seed from proof of time in case entropy injection is not needed
282    #[inline]
283    pub fn seed(&self) -> PotSeed {
284        PotSeed(self.0)
285    }
286
287    /// Derive seed from proof of time with entropy injection
288    #[inline]
289    pub fn seed_with_entropy(&self, entropy: &Blake3Hash) -> PotSeed {
290        let hash = blake3_hash_list(&[entropy.as_ref(), &self.0]);
291        let mut seed = PotSeed::default();
292        seed.copy_from_slice(&hash[..Self::SIZE]);
293        seed
294    }
295
296    /// Convenient conversion from slice of underlying representation for efficiency purposes
297    #[inline(always)]
298    pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
299        // SAFETY: `PotOutput` is `#[repr(C)]` and guaranteed to have the same memory layout
300        unsafe { mem::transmute(value) }
301    }
302
303    /// Convenient conversion to slice of underlying representation for efficiency purposes
304    #[inline(always)]
305    pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
306        // SAFETY: `PotOutput` is `#[repr(C)]` and guaranteed to have the same memory layout
307        unsafe { mem::transmute(value) }
308    }
309}
310
311/// Proof of time checkpoints, result of proving
312#[derive(
313    Debug,
314    Default,
315    Copy,
316    Clone,
317    Eq,
318    PartialEq,
319    Hash,
320    Deref,
321    DerefMut,
322    Encode,
323    Decode,
324    TypeInfo,
325    MaxEncodedLen,
326)]
327pub struct PotCheckpoints([PotOutput; Self::NUM_CHECKPOINTS.get() as usize]);
328
329impl PotCheckpoints {
330    /// Number of PoT checkpoints produced (used to optimize verification)
331    pub const NUM_CHECKPOINTS: NonZeroU8 = NonZeroU8::new(8).expect("Not zero; qed");
332
333    /// Get proof of time output out of checkpoints (last checkpoint)
334    #[inline]
335    pub fn output(&self) -> PotOutput {
336        self.0[Self::NUM_CHECKPOINTS.get() as usize - 1]
337    }
338}