1#![cfg_attr(
4 any(target_arch = "aarch64", target_arch = "x86_64"),
5 feature(portable_simd)
6)]
7#![no_std]
8
9mod aes;
10
11use ab_core_primitives::pot::{PotCheckpoints, PotSeed};
12use core::num::NonZeroU32;
13
14#[derive(Debug, thiserror::Error)]
16pub enum PotError {
17 #[error(
19 "Iterations {iterations} are not multiple of number of checkpoints {num_checkpoints} \
20 times two"
21 )]
22 NotMultipleOfCheckpoints {
23 iterations: NonZeroU32,
25 num_checkpoints: u32,
27 },
28}
29
30#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
34pub fn prove(seed: PotSeed, iterations: NonZeroU32) -> Result<PotCheckpoints, PotError> {
35 if !iterations
36 .get()
37 .is_multiple_of(u32::from(PotCheckpoints::NUM_CHECKPOINTS.get() * 2))
38 {
39 return Err(PotError::NotMultipleOfCheckpoints {
40 iterations,
41 num_checkpoints: u32::from(PotCheckpoints::NUM_CHECKPOINTS.get()),
42 });
43 }
44
45 Ok(aes::create(
47 seed,
48 seed.key(),
49 iterations.get() / u32::from(PotCheckpoints::NUM_CHECKPOINTS.get()),
50 ))
51}
52
53#[cfg_attr(
58 all(feature = "no-panic", not(target_os = "macos")),
59 no_panic::no_panic
60)]
61pub fn verify(
62 seed: PotSeed,
63 iterations: NonZeroU32,
64 checkpoints: &PotCheckpoints,
65) -> Result<bool, PotError> {
66 let num_checkpoints = checkpoints.len() as u32;
67 if !iterations.get().is_multiple_of(num_checkpoints * 2) {
68 return Err(PotError::NotMultipleOfCheckpoints {
69 iterations,
70 num_checkpoints,
71 });
72 }
73
74 Ok(aes::verify_sequential(
75 seed,
76 seed.key(),
77 checkpoints,
78 iterations.get() / num_checkpoints,
79 ))
80}