ab_proof_of_time/
lib.rs

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