ab_proof_of_time/
lib.rs

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