1#[cfg(all(feature = "std", target_arch = "x86_64"))]
4mod x86_64;
5
6#[cfg(not(feature = "std"))]
7extern crate alloc;
8
9use aes::cipher::array::Array;
10use aes::cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
11use aes::Aes128;
12#[cfg(not(feature = "std"))]
13use alloc::vec::Vec;
14use subspace_core_primitives::pot::{PotCheckpoints, PotKey, PotOutput, PotSeed};
15
16#[inline(always)]
18pub(crate) fn create(seed: PotSeed, key: PotKey, checkpoint_iterations: u32) -> PotCheckpoints {
19 #[cfg(all(feature = "std", target_arch = "x86_64"))]
20 if std::is_x86_feature_detected!("aes") {
21 return unsafe { x86_64::create(seed.as_ref(), key.as_ref(), checkpoint_iterations) };
22 }
23
24 create_generic(seed, key, checkpoint_iterations)
25}
26
27fn create_generic(seed: PotSeed, key: PotKey, checkpoint_iterations: u32) -> PotCheckpoints {
28 let key = Array::from(*key);
29 let cipher = Aes128::new(&key);
30 let mut cur_block = Array::from(*seed);
31
32 let mut checkpoints = PotCheckpoints::default();
33 for checkpoint in checkpoints.iter_mut() {
34 for _ in 0..checkpoint_iterations {
35 cipher.encrypt_block(&mut cur_block);
37 }
38 checkpoint.copy_from_slice(&cur_block);
39 }
40
41 checkpoints
42}
43
44#[inline(always)]
48pub(crate) fn verify_sequential(
49 seed: PotSeed,
50 key: PotKey,
51 checkpoints: &[PotOutput],
52 checkpoint_iterations: u32,
53) -> bool {
54 assert_eq!(checkpoint_iterations % 2, 0);
55
56 let key = Array::from(*key);
57 let cipher = Aes128::new(&key);
58
59 let mut inputs = Vec::with_capacity(checkpoints.len());
60 inputs.push(Array::from(*seed));
61 for &checkpoint in checkpoints.iter().rev().skip(1).rev() {
62 inputs.push(Array::from(*checkpoint));
63 }
64 let mut outputs = checkpoints
65 .iter()
66 .map(|&checkpoint| Array::from(*checkpoint))
67 .collect::<Vec<_>>();
68
69 for _ in 0..checkpoint_iterations / 2 {
70 cipher.encrypt_blocks(&mut inputs);
71 cipher.decrypt_blocks(&mut outputs);
72 }
73
74 inputs == outputs
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 const SEED: [u8; 16] = [
82 0xd6, 0x66, 0xcc, 0xd8, 0xd5, 0x93, 0xc2, 0x3d, 0xa8, 0xdb, 0x6b, 0x5b, 0x14, 0x13, 0xb1,
83 0x3a,
84 ];
85 const SEED_1: [u8; 16] = [
86 0xd7, 0xd6, 0xdc, 0xd8, 0xd5, 0x93, 0xc2, 0x3d, 0xa8, 0xdb, 0x6b, 0x5b, 0x14, 0x13, 0xb1,
87 0x3a,
88 ];
89 const KEY: [u8; 16] = [
90 0x9a, 0x84, 0x94, 0x0f, 0xfe, 0xf5, 0xb0, 0xd7, 0x01, 0x99, 0xfc, 0x67, 0xf4, 0x6e, 0xa2,
91 0x7a,
92 ];
93 const KEY_1: [u8; 16] = [
94 0x9b, 0x8b, 0x9b, 0x0f, 0xfe, 0xf5, 0xb0, 0xd7, 0x01, 0x99, 0xfc, 0x67, 0xf4, 0x6e, 0xa2,
95 0x7a,
96 ];
97 const BAD_CIPHER: [u8; 16] = [22; 16];
98
99 #[test]
100 fn test_create_verify() {
101 let seed = PotSeed::from(SEED);
102 let key = PotKey::from(KEY);
103 let checkpoint_iterations = 100;
104
105 let checkpoints = create(seed, key, checkpoint_iterations);
107 {
108 let generic_checkpoints = create_generic(seed, key, checkpoint_iterations);
109 assert_eq!(checkpoints, generic_checkpoints);
110 }
111
112 assert!(verify_sequential(
113 seed,
114 key,
115 &*checkpoints,
116 checkpoint_iterations,
117 ));
118
119 let mut checkpoints_1 = checkpoints;
121 checkpoints_1[0] = PotOutput::from(BAD_CIPHER);
122 assert!(!verify_sequential(
123 seed,
124 key,
125 &*checkpoints_1,
126 checkpoint_iterations,
127 ));
128
129 assert!(!verify_sequential(
131 seed,
132 key,
133 &*checkpoints,
134 checkpoint_iterations + 2,
135 ));
136 assert!(!verify_sequential(
137 seed,
138 key,
139 &*checkpoints,
140 checkpoint_iterations - 2,
141 ));
142
143 assert!(!verify_sequential(
145 PotSeed::from(SEED_1),
146 key,
147 &*checkpoints,
148 checkpoint_iterations,
149 ));
150
151 assert!(!verify_sequential(
153 seed,
154 PotKey::from(KEY_1),
155 &*checkpoints,
156 checkpoint_iterations,
157 ));
158 }
159}