1#![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#[derive(Debug, thiserror::Error)]
19pub enum PotError {
20 #[error(
22 "Iterations {iterations} are not multiple of number of checkpoints {num_checkpoints} \
23 times two"
24 )]
25 NotMultipleOfCheckpoints {
26 iterations: NonZeroU32,
28 num_checkpoints: u32,
30 },
31}
32
33#[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 Ok(aes::create(
50 seed,
51 seed.key(),
52 iterations.get() / u32::from(PotCheckpoints::NUM_CHECKPOINTS.get()),
53 ))
54}
55
56#[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}