Background
A perf profile of the 3,000,000-request pi_basic workload attributes approximately:
- 24.06% inclusive CPU to
CommittableTx::serialise()
- 9.50% inclusive CPU to AES-GCM encryption
- 6.06% inclusive CPU to the AES EVP/provider initialisation path
- 0.97% inclusive CPU to AES context allocation/free/reset
KeyAesGcm_OpenSSL retains the raw key and an EVP_CIPHER*, but each encrypt()/decrypt() creates a new EVP_CIPHER_CTX and fully initialises the provider and key again.
A standalone microbenchmark forced through symcryptprovider produced identical ciphertext and GCM tags while reducing 64-byte encryption from 873.5 ns/op to 228.9 ns/op (3.82x) by retaining keyed context state and reinitialising only with the next unique IV.
Proposed implementation
- Make each
KeyAesGcm_OpenSSL own a small set of pre-keyed encryption contexts, one per active CCF worker thread (or an equivalent bounded pool).
- Keep encryption and decryption contexts separate.
- Fully initialise each context once for its key/provider, then begin each operation with IV-only reinitialisation (
EVP_EncryptInit_ex2(ctx, nullptr, nullptr, iv, nullptr) or the equivalent decrypt call).
- Continue deriving unique GCM IVs from transaction view/seqno/type exactly as today.
- Explicitly fetch and own the provider cipher once per key if this avoids implicit provider lookup while preserving configured provider selection.
- Ensure context ownership remains with the key object, rather than an unbounded
thread_local map, so rollback/rekey destruction releases and cleanses all expanded key state.
- Avoid a single shared mutable context: ledger key objects are used concurrently by multiple enclave workers.
Correctness and security coverage
Add tests for:
- Byte-for-byte equivalence with the existing fresh-context path.
- Concurrent encrypt/decrypt on multiple workers.
- Rekeying and switching between current and historical ledger secrets.
- Rollback removing a key and its cached contexts.
- Context recovery after a failed authenticated decryption.
- Empty plaintext/AAD combinations supported by the current API.
- Default and SymCrypt provider configurations.
Measure the change independently with the existing crypto benchmarks and an A/B pi_basic run/profile.
Out of scope
Commit-evidence HMAC also appears in the profile (6.68% inclusive), but only about 1.47% is currently attributable to HMAC initialisation/context allocation. Track it only if a focused benchmark demonstrates a worthwhile end-to-end gain after the AES-GCM work.
Background
A
perfprofile of the 3,000,000-requestpi_basicworkload attributes approximately:CommittableTx::serialise()KeyAesGcm_OpenSSLretains the raw key and anEVP_CIPHER*, but eachencrypt()/decrypt()creates a newEVP_CIPHER_CTXand fully initialises the provider and key again.A standalone microbenchmark forced through
symcryptproviderproduced identical ciphertext and GCM tags while reducing 64-byte encryption from 873.5 ns/op to 228.9 ns/op (3.82x) by retaining keyed context state and reinitialising only with the next unique IV.Proposed implementation
KeyAesGcm_OpenSSLown a small set of pre-keyed encryption contexts, one per active CCF worker thread (or an equivalent bounded pool).EVP_EncryptInit_ex2(ctx, nullptr, nullptr, iv, nullptr)or the equivalent decrypt call).thread_localmap, so rollback/rekey destruction releases and cleanses all expanded key state.Correctness and security coverage
Add tests for:
Measure the change independently with the existing crypto benchmarks and an A/B
pi_basicrun/profile.Out of scope
Commit-evidence HMAC also appears in the profile (6.68% inclusive), but only about 1.47% is currently attributable to HMAC initialisation/context allocation. Track it only if a focused benchmark demonstrates a worthwhile end-to-end gain after the AES-GCM work.