|
4 | 4 | * All rights reserved. |
5 | 5 | **********************************************************************************************/ |
6 | 6 |
|
| 7 | +use constcat::concat; |
7 | 8 | use criterion::{Criterion, criterion_group, criterion_main}; |
8 | 9 | use std::{ |
9 | 10 | hint::black_box, |
| 11 | + num::NonZeroUsize, |
10 | 12 | sync::atomic::{AtomicUsize, Ordering}, |
11 | 13 | time::Duration, |
12 | 14 | }; |
13 | 15 | use tss2_fapi_rs::{BaseErrorCode, ErrorCode, FapiContext, KeyFlags}; |
14 | 16 |
|
15 | | -const BASE_KEY_PATH: &str = "HS/SRK/bench"; |
16 | | -const SIGN_KEY_PATH: &str = "HS/SRK/sign_key"; |
17 | | - |
18 | 17 | // ========================================================================== |
19 | | -// Bench #1: Create key |
| 18 | +// Benchmarks |
20 | 19 | // ========================================================================== |
21 | 20 |
|
22 | | -fn bench_create_key(c: &mut Criterion) { |
| 21 | +const BASE_KEY_PATH: &str = "HS/SRK/my_bench"; |
| 22 | +const SIGN_KEY_PATH: &str = concat!(BASE_KEY_PATH, "/sign_key"); |
| 23 | + |
| 24 | +/// Benchmark #1: Get random |
| 25 | +/// ------------------------ |
| 26 | +/// This benchmark measures the performance of the [`FapiContext::get_random()`] function. |
| 27 | +fn bench_get_random(c: &mut Criterion) { |
23 | 28 | // Create a new FAPI context |
24 | 29 | let mut context = FapiContext::new().expect("Failed to create context!"); |
25 | 30 |
|
26 | | - // Perform the provisioning, if it has not been done yet |
27 | | - match context.provision(None, None, None) { |
28 | | - Ok(_) => (), |
29 | | - Err(ErrorCode::FapiError(BaseErrorCode::AlreadyProvisioned)) => (), |
30 | | - Err(error) => panic!("Provisioning has failed: {:?}", error), |
31 | | - } |
| 31 | + // Initialize TPM |
| 32 | + let manager = TpmManager::new(&mut context); |
32 | 33 |
|
33 | | - // Delete existing storage key |
34 | | - match context.delete(BASE_KEY_PATH) { |
35 | | - Ok(_) => (), |
36 | | - Err(ErrorCode::FapiError(BaseErrorCode::BadPath)) => (), |
37 | | - Err(ErrorCode::FapiError(BaseErrorCode::PathNotFound)) => (), |
38 | | - Err(error) => panic!("Failed to delete: {:?}", error), |
39 | | - } |
| 34 | + // Measurement! |
| 35 | + let counter: AtomicUsize = AtomicUsize::new(0usize); |
| 36 | + c.bench_function("get_random", |b| b.iter(|| _get_random(manager.0, black_box(counter.fetch_add(1usize, Ordering::Relaxed))))); |
| 37 | +} |
| 38 | + |
| 39 | +fn _get_random(context: &mut FapiContext, _n: usize) { |
| 40 | + let length = unsafe { NonZeroUsize::new(32usize).unwrap_unchecked() }; |
| 41 | + let _buffer = black_box(context.get_random(length).expect("Failed to get random data!")); |
| 42 | +} |
| 43 | + |
| 44 | +/// Benchmark #2: Create key |
| 45 | +/// ------------------------ |
| 46 | +/// This benchmark measures the performance of the [`FapiContext::create_key()`] function. |
| 47 | +fn bench_create_key(c: &mut Criterion) { |
| 48 | + // Create a new FAPI context |
| 49 | + let mut context = FapiContext::new().expect("Failed to create context!"); |
40 | 50 |
|
41 | | - // Create storage key |
42 | | - context.create_key(BASE_KEY_PATH, Some(&[KeyFlags::Decrypt, KeyFlags::Restricted, KeyFlags::NoDA]), None, None).expect("Failed to create parent key!"); |
| 51 | + // Initialize TPM |
| 52 | + let manager = TpmManager::new(&mut context); |
43 | 53 |
|
44 | | - // Create the siging keys |
| 54 | + // Measurement! |
45 | 55 | let counter: AtomicUsize = AtomicUsize::new(0usize); |
46 | | - c.bench_function("create_key", |b| b.iter(|| _create_key(&mut context, black_box(counter.fetch_add(1usize, Ordering::Relaxed))))); |
| 56 | + c.bench_function("create_key", |b| b.iter(|| _create_key(manager.0, black_box(counter.fetch_add(1usize, Ordering::Relaxed))))); |
47 | 57 | } |
48 | 58 |
|
49 | 59 | fn _create_key(context: &mut FapiContext, n: usize) { |
50 | 60 | const MY_KEYFLAG: &[KeyFlags] = &[KeyFlags::Sign, KeyFlags::NoDA]; |
51 | 61 | context.create_key(&format!("{}/key_{}", BASE_KEY_PATH, n), Some(MY_KEYFLAG), None, None).expect("Failed to create key!") |
52 | 62 | } |
53 | 63 |
|
54 | | -// ========================================================================== |
55 | | -// Bench #2: Sign |
56 | | -// ========================================================================== |
57 | | - |
| 64 | +/// Benchmark #3: Sign |
| 65 | +/// ------------------ |
| 66 | +/// This benchmark measures the performance of the [`FapiContext::sign()`] function. |
58 | 67 | fn bench_sign(c: &mut Criterion) { |
59 | 68 | // Create a new FAPI context |
60 | 69 | let mut context = FapiContext::new().expect("Failed to create context!"); |
61 | 70 |
|
62 | | - // Perform the provisioning, if it has not been done yet |
63 | | - match context.provision(None, None, None) { |
64 | | - Ok(_) => (), |
65 | | - Err(ErrorCode::FapiError(BaseErrorCode::AlreadyProvisioned)) => (), |
66 | | - Err(error) => panic!("Provisioning has failed: {:?}", error), |
67 | | - } |
68 | | - |
69 | | - // Delete existing key |
70 | | - match context.delete(SIGN_KEY_PATH) { |
71 | | - Ok(_) => (), |
72 | | - Err(ErrorCode::FapiError(BaseErrorCode::BadPath)) => (), |
73 | | - Err(ErrorCode::FapiError(BaseErrorCode::PathNotFound)) => (), |
74 | | - Err(error) => panic!("Failed to delete: {:?}", error), |
75 | | - } |
| 71 | + // Initialize TPM |
| 72 | + let manager = TpmManager::new(&mut context); |
76 | 73 |
|
77 | 74 | // Create siging key |
78 | | - context.create_key(SIGN_KEY_PATH, Some(&[KeyFlags::Sign, KeyFlags::NoDA]), None, None).expect("Failed to create sign key!"); |
| 75 | + manager.0.create_key(SIGN_KEY_PATH, Some(&[KeyFlags::Sign, KeyFlags::NoDA]), None, None).expect("Failed to create sign key!"); |
79 | 76 |
|
80 | | - // Sign message |
| 77 | + // Measurement! |
81 | 78 | let counter: AtomicUsize = AtomicUsize::new(0usize); |
82 | | - c.bench_function("sign", |b| b.iter(|| _sign(&mut context, black_box(counter.fetch_add(1usize, Ordering::Relaxed))))); |
| 79 | + c.bench_function("sign", |b| b.iter(|| _sign(manager.0, black_box(counter.fetch_add(1usize, Ordering::Relaxed))))); |
83 | 80 | } |
84 | 81 |
|
85 | 82 | fn _sign(context: &mut FapiContext, n: usize) { |
86 | 83 | let mut digest = [0u8; 32usize]; |
87 | 84 | digest[..size_of::<usize>()].copy_from_slice(&n.to_be_bytes()); |
88 | | - let _signature = context.sign(SIGN_KEY_PATH, None, &digest, false, false).expect("Failed to sign message!"); |
| 85 | + let _signature = black_box(context.sign(SIGN_KEY_PATH, None, &digest, false, false).expect("Failed to sign message!")); |
89 | 86 | } |
90 | 87 |
|
91 | | -// ========================================================================== |
92 | | -// Bench #3: Verify |
93 | | -// ========================================================================== |
94 | | - |
| 88 | +/// Benchmark #4: Verify signature |
| 89 | +/// ------------------------------ |
| 90 | +/// This benchmark measures the performance of the [`FapiContext::verify_signature()`] function. |
95 | 91 | fn bench_verify_signature(c: &mut Criterion) { |
96 | 92 | // Create a new FAPI context |
97 | 93 | let mut context = FapiContext::new().expect("Failed to create context!"); |
98 | 94 |
|
99 | | - // Perform the provisioning, if it has not been done yet |
100 | | - match context.provision(None, None, None) { |
101 | | - Ok(_) => (), |
102 | | - Err(ErrorCode::FapiError(BaseErrorCode::AlreadyProvisioned)) => (), |
103 | | - Err(error) => panic!("Provisioning has failed: {:?}", error), |
104 | | - } |
105 | | - |
106 | | - // Delete existing key |
107 | | - match context.delete(SIGN_KEY_PATH) { |
108 | | - Ok(_) => (), |
109 | | - Err(ErrorCode::FapiError(BaseErrorCode::BadPath)) => (), |
110 | | - Err(ErrorCode::FapiError(BaseErrorCode::PathNotFound)) => (), |
111 | | - Err(error) => panic!("Failed to delete: {:?}", error), |
112 | | - } |
| 95 | + // Initialize TPM |
| 96 | + let manager = TpmManager::new(&mut context); |
113 | 97 |
|
114 | 98 | // Create siging key |
115 | | - context.create_key(SIGN_KEY_PATH, Some(&[KeyFlags::Sign, KeyFlags::NoDA]), None, None).expect("Failed to create sign key!"); |
| 99 | + manager.0.create_key(SIGN_KEY_PATH, Some(&[KeyFlags::Sign, KeyFlags::NoDA]), None, None).expect("Failed to create sign key!"); |
116 | 100 |
|
117 | 101 | // Sign message |
118 | 102 | let digest = [0u8; 32usize]; |
119 | | - let signature = context.sign(SIGN_KEY_PATH, None, &digest, false, false).expect("Failed to sign message!"); |
| 103 | + let signature = manager.0.sign(SIGN_KEY_PATH, None, &digest, false, false).expect("Failed to sign message!"); |
120 | 104 |
|
121 | | - // Verify signature |
122 | | - c.bench_function("verify_signature", |b| b.iter(|| _verify_signature(&mut context, black_box(&digest), &black_box(&signature).sign_value))); |
| 105 | + // Measurement! |
| 106 | + c.bench_function("verify_signature", |b| b.iter(|| _verify_signature(manager.0, black_box(&digest), &black_box(&signature).sign_value))); |
123 | 107 | } |
124 | 108 |
|
125 | 109 | fn _verify_signature(context: &mut FapiContext, digest: &[u8], signature: &[u8]) { |
126 | | - let result = context.verify_signature(SIGN_KEY_PATH, digest, signature).expect("Failed to verify signature!"); |
| 110 | + let result = black_box(context.verify_signature(SIGN_KEY_PATH, digest, signature).expect("Failed to verify signature!")); |
127 | 111 | assert!(result); |
128 | 112 | } |
129 | 113 |
|
| 114 | +// ========================================================================== |
| 115 | +// Utility functions |
| 116 | +// ========================================================================== |
| 117 | + |
| 118 | +struct TpmManager<'a>(pub &'a mut FapiContext); |
| 119 | + |
| 120 | +impl<'a> TpmManager<'a> { |
| 121 | + pub fn new(context: &'a mut FapiContext) -> Self { |
| 122 | + // Perform the provisioning, if it has not been done yet |
| 123 | + match context.provision(None, None, None) { |
| 124 | + Ok(_) => (), |
| 125 | + Err(ErrorCode::FapiError(BaseErrorCode::AlreadyProvisioned)) => (), |
| 126 | + Err(error) => panic!("Provisioning has failed: {:?}", error), |
| 127 | + } |
| 128 | + |
| 129 | + // Delete existing storage key, if it already exists |
| 130 | + Self::clean_up(context).expect("Failed to delete the existing key!"); |
| 131 | + |
| 132 | + // Create our storage key |
| 133 | + context.create_key(BASE_KEY_PATH, Some(&[KeyFlags::Decrypt, KeyFlags::Restricted, KeyFlags::NoDA]), None, None).expect("Failed to create parent key!"); |
| 134 | + Self(context) |
| 135 | + } |
| 136 | + |
| 137 | + fn clean_up(context: &mut FapiContext) -> Result<(), ErrorCode> { |
| 138 | + match context.delete(BASE_KEY_PATH) { |
| 139 | + Ok(_) => Ok(()), |
| 140 | + Err(ErrorCode::FapiError(BaseErrorCode::BadPath | BaseErrorCode::PathNotFound | BaseErrorCode::KeyNotFound)) => Ok(()), |
| 141 | + Err(error) => Err(error), |
| 142 | + } |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +impl<'a> Drop for TpmManager<'a> { |
| 147 | + fn drop(&mut self) { |
| 148 | + _ = Self::clean_up(self.0); |
| 149 | + } |
| 150 | +} |
| 151 | + |
130 | 152 | // ========================================================================== |
131 | 153 | // Main |
132 | 154 | // ========================================================================== |
133 | 155 |
|
134 | 156 | fn create_config() -> Criterion { |
135 | | - Criterion::default().warm_up_time(Duration::from_secs(15)).measurement_time(Duration::from_secs(30)).noise_threshold(0.1).without_plots() |
| 157 | + Criterion::default().warm_up_time(Duration::from_secs(25)).measurement_time(Duration::from_secs(120)).noise_threshold(0.1).without_plots() |
136 | 158 | } |
137 | 159 |
|
138 | | -criterion_group!(name = benches; config = create_config(); targets = bench_create_key, bench_sign, bench_verify_signature); |
| 160 | +criterion_group!(name = benches; config = create_config(); targets = bench_get_random, bench_create_key, bench_sign, bench_verify_signature); |
139 | 161 | criterion_main!(benches); |
0 commit comments