ab_proof_of_time/
lib.rs

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