subspace_core_primitives/
pot.rs

1//! Proof of time-related data structures.
2
3use crate::hashes::{blake3_hash, blake3_hash_list, Blake3Hash};
4use crate::Randomness;
5use core::fmt;
6use core::num::NonZeroU8;
7use core::str::FromStr;
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)]
216pub struct PotOutput([u8; Self::SIZE]);
217
218impl fmt::Debug for PotOutput {
219    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220        write!(f, "{}", hex::encode(self.0))
221    }
222}
223
224#[cfg(feature = "serde")]
225#[derive(Serialize, Deserialize)]
226#[serde(transparent)]
227struct PotOutputBinary([u8; PotOutput::SIZE]);
228
229#[cfg(feature = "serde")]
230#[derive(Serialize, Deserialize)]
231#[serde(transparent)]
232struct PotOutputHex(#[serde(with = "hex")] [u8; PotOutput::SIZE]);
233
234#[cfg(feature = "serde")]
235impl Serialize for PotOutput {
236    #[inline]
237    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238    where
239        S: Serializer,
240    {
241        if serializer.is_human_readable() {
242            PotOutputHex(self.0).serialize(serializer)
243        } else {
244            PotOutputBinary(self.0).serialize(serializer)
245        }
246    }
247}
248
249#[cfg(feature = "serde")]
250impl<'de> Deserialize<'de> for PotOutput {
251    #[inline]
252    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
253    where
254        D: Deserializer<'de>,
255    {
256        Ok(Self(if deserializer.is_human_readable() {
257            PotOutputHex::deserialize(deserializer)?.0
258        } else {
259            PotOutputBinary::deserialize(deserializer)?.0
260        }))
261    }
262}
263
264impl fmt::Display for PotOutput {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        write!(f, "{}", hex::encode(self.0))
267    }
268}
269
270impl PotOutput {
271    /// Size of proof of time proof in bytes
272    pub const SIZE: usize = 16;
273
274    /// Derives the global randomness from the output
275    #[inline]
276    pub fn derive_global_randomness(&self) -> Randomness {
277        Randomness::from(*blake3_hash(&self.0))
278    }
279
280    /// Derive seed from proof of time in case entropy injection is not needed
281    #[inline]
282    pub fn seed(&self) -> PotSeed {
283        PotSeed(self.0)
284    }
285
286    /// Derive seed from proof of time with entropy injection
287    #[inline]
288    pub fn seed_with_entropy(&self, entropy: &Blake3Hash) -> PotSeed {
289        let hash = blake3_hash_list(&[entropy.as_ref(), &self.0]);
290        let mut seed = PotSeed::default();
291        seed.copy_from_slice(&hash[..Self::SIZE]);
292        seed
293    }
294}
295
296/// Proof of time checkpoints, result of proving
297#[derive(
298    Debug,
299    Default,
300    Copy,
301    Clone,
302    Eq,
303    PartialEq,
304    Hash,
305    Deref,
306    DerefMut,
307    Encode,
308    Decode,
309    TypeInfo,
310    MaxEncodedLen,
311)]
312pub struct PotCheckpoints([PotOutput; Self::NUM_CHECKPOINTS.get() as usize]);
313
314impl PotCheckpoints {
315    /// Number of PoT checkpoints produced (used to optimize verification)
316    pub const NUM_CHECKPOINTS: NonZeroU8 = NonZeroU8::new(8).expect("Not zero; qed");
317
318    /// Get proof of time output out of checkpoints (last checkpoint)
319    #[inline]
320    pub fn output(&self) -> PotOutput {
321        self.0[Self::NUM_CHECKPOINTS.get() as usize - 1]
322    }
323}