subspace_proof_of_time/
lib.rs

1//! Proof of time implementation.
2
3#![cfg_attr(not(feature = "std"), no_std)]
4mod aes;
5
6use core::num::NonZeroU32;
7use subspace_core_primitives::pot::{PotCheckpoints, PotOutput, PotSeed};
8
9/// Proof of time error
10#[derive(Debug, thiserror::Error)]
11pub enum PotError {
12    /// Iterations are not multiple of number of checkpoints times two
13    #[error(
14        "Iterations {iterations} are not multiple of number of checkpoints {num_checkpoints} \
15        times two"
16    )]
17    NotMultipleOfCheckpoints {
18        /// Slot iterations provided
19        iterations: NonZeroU32,
20        /// Number of checkpoints
21        num_checkpoints: u32,
22    },
23}
24
25/// Run PoT proving and produce checkpoints.
26///
27/// Returns error if `iterations` is not a multiple of checkpoints times two.
28pub fn prove(seed: PotSeed, iterations: NonZeroU32) -> Result<PotCheckpoints, PotError> {
29    if iterations.get() % u32::from(PotCheckpoints::NUM_CHECKPOINTS.get() * 2) != 0 {
30        return Err(PotError::NotMultipleOfCheckpoints {
31            iterations,
32            num_checkpoints: u32::from(PotCheckpoints::NUM_CHECKPOINTS.get()),
33        });
34    }
35
36    Ok(aes::create(
37        seed,
38        seed.key(),
39        iterations.get() / u32::from(PotCheckpoints::NUM_CHECKPOINTS.get()),
40    ))
41}
42
43/// Verify checkpoint, number of iterations is set across uniformly distributed checkpoints.
44///
45/// Returns error if `iterations` is not a multiple of checkpoints times two.
46pub fn verify(
47    seed: PotSeed,
48    iterations: NonZeroU32,
49    checkpoints: &[PotOutput],
50) -> Result<bool, PotError> {
51    let num_checkpoints = checkpoints.len() as u32;
52    if iterations.get() % (num_checkpoints * 2) != 0 {
53        return Err(PotError::NotMultipleOfCheckpoints {
54            iterations,
55            num_checkpoints,
56        });
57    }
58
59    Ok(aes::verify_sequential(
60        seed,
61        seed.key(),
62        checkpoints,
63        iterations.get() / num_checkpoints,
64    ))
65}