subspace_proof_of_time/
aes.rs

1//! AES related functionality.
2
3#[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/// Creates the AES based proof.
17#[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            // Encrypt in place to produce the next block.
36            cipher.encrypt_block(&mut cur_block);
37        }
38        checkpoint.copy_from_slice(&cur_block);
39    }
40
41    checkpoints
42}
43
44/// Verifies the AES based proof sequentially.
45///
46/// Panics if `checkpoint_iterations` is not a multiple of `2`.
47#[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        // Can encrypt/decrypt.
106        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        // Decryption of invalid cipher text fails.
120        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        // Decryption with wrong number of iterations fails.
130        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        // Decryption with wrong seed fails.
144        assert!(!verify_sequential(
145            PotSeed::from(SEED_1),
146            key,
147            &*checkpoints,
148            checkpoint_iterations,
149        ));
150
151        // Decryption with wrong key fails.
152        assert!(!verify_sequential(
153            seed,
154            PotKey::from(KEY_1),
155            &*checkpoints,
156            checkpoint_iterations,
157        ));
158    }
159}