Skip to main content

ab_proof_of_time/
lib.rs

1//! Proof of time implementation.
2
3#![cfg_attr(
4    any(
5        all(not(miri), target_arch = "aarch64"),
6        all(not(miri), target_arch = "x86_64")
7    ),
8    feature(portable_simd)
9)]
10#![no_std]
11
12mod aes;
13
14use ab_core_primitives::pot::{PotCheckpoints, PotSeed};
15use core::num::NonZeroU32;
16
17/// Proof of time error
18#[derive(Debug, thiserror::Error)]
19pub enum PotError {
20    /// Iterations are not multiple of number of checkpoints times two
21    #[error(
22        "Iterations {iterations} are not multiple of number of checkpoints {num_checkpoints} \
23        times two"
24    )]
25    NotMultipleOfCheckpoints {
26        /// Slot iterations provided
27        iterations: NonZeroU32,
28        /// Number of checkpoints
29        num_checkpoints: u32,
30    },
31}
32
33/// Run PoT proving and produce checkpoints.
34///
35/// Returns error if `iterations` is not a multiple of checkpoints times two.
36#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
37pub fn prove(seed: PotSeed, iterations: NonZeroU32) -> Result<PotCheckpoints, PotError> {
38    if !iterations
39        .get()
40        .is_multiple_of(u32::from(PotCheckpoints::NUM_CHECKPOINTS.get() * 2))
41    {
42        return Err(PotError::NotMultipleOfCheckpoints {
43            iterations,
44            num_checkpoints: u32::from(PotCheckpoints::NUM_CHECKPOINTS.get()),
45        });
46    }
47
48    // TODO: Is there a point in having both values derived from the same source?
49    Ok(aes::create(
50        seed,
51        seed.key(),
52        iterations.get() / u32::from(PotCheckpoints::NUM_CHECKPOINTS.get()),
53    ))
54}
55
56/// Verify checkpoint, number of iterations is set across uniformly distributed checkpoints.
57///
58/// Returns error if `iterations` is not a multiple of checkpoints times two.
59// TODO: Figure out what is wrong with macOS here
60#[cfg_attr(
61    all(feature = "no-panic", not(target_os = "macos")),
62    no_panic::no_panic
63)]
64pub fn verify(
65    seed: PotSeed,
66    iterations: NonZeroU32,
67    checkpoints: &PotCheckpoints,
68) -> Result<bool, PotError> {
69    let num_checkpoints = checkpoints.len() as u32;
70    if !iterations.get().is_multiple_of(num_checkpoints * 2) {
71        return Err(PotError::NotMultipleOfCheckpoints {
72            iterations,
73            num_checkpoints,
74        });
75    }
76
77    Ok(aes::verify_sequential(
78        seed,
79        seed.key(),
80        checkpoints,
81        iterations.get() / num_checkpoints,
82    ))
83}