You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As my test via cargo bench, the aes-gcm-256's performance is much worse:
Running target/release/deps/simple-75040055ea8811ad
Gnuplot not found, using plotters backend
encrypt 100M time: [174.63 ms 175.52 ms 176.60 ms]
change: [+128.80% +133.74% +138.22%] (p = 0.00 < 0.05)
Performance has regressed.
Found 1 outliers among 10 measurements (10.00%)
1 (10.00%) high mild
decrypt 100M time: [137.44 ms 138.20 ms 138.90 ms]
change: [+291.03% +294.15% +297.13%] (p = 0.00 < 0.05)
Performance has regressed.
It was built with export RUSTFLAGS="-Ctarget-cpu=sandybridge -Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3" as documented.
For OpenSSL:
Running target/release/deps/simple-8072f89159d02aed
Gnuplot not found, using plotters backend
encrypt 100M time: [73.289 ms 73.619 ms 74.055 ms]
change: [-2.1748% -0.9188% +0.3013%] (p = 0.18 > 0.05)
No change in performance detected.
Found 1 outliers among 10 measurements (10.00%)
1 (10.00%) high mild
decrypt 100M time: [35.428 ms 35.591 ms 35.757 ms]
change: [-0.3106% +0.1991% +0.7224%] (p = 0.47 > 0.05)
No change in performance detected.
We are working on and have partially implemented autodetection support for these CPU features which will eliminate the need to manually configure RUSTFLAGS and will be available in the next release.
I'm not sure that much of a difference deserves the qualifier "much".
We've presently been working on features like CPU feature autodetection (which are important) and haven't heavily invested in micro-optimization.
OpenSSL uses heavily optimized hand-written assembly implementations (in the case of AES-GCM, written by cryptography engineers at Intel), so reaching performance parity with those (especially in pure Rust) will be difficult.
In my experience target-cpu=native often results in a degraded performance (one possible explanation is CPU down-clocking due to the AVX2 instructions being used here and there), so I would be careful with it.
Also note: for optimum performance, pass Ctarget-cpu=native.
This will significantly improve performance on Skylake, where LLVM will use the VPCLMULQDQ instruction for GHASH.
I didn't see any statistically significant difference on iMac 2019, thanks anyway :)
encrypt 100M time: [177.03 ms 178.43 ms 181.16 ms]
change: [-0.7220% +0.7965% +2.4234%] (p = 0.36 > 0.05)
No change in performance detected.
Benchmarking encrypt 200M: Warming up for 3.0000 s
Warning: Unable to complete 10 samples in 20.0s. You may wish to increase target time to 20.0sor enable flat sampling.
encrypt 200M time: [349.32 ms 353.57 ms 356.14 ms]
change: [-2.5313% -1.6411% -0.7211%] (p = 0.00 < 0.05)
Change within noise threshold.
decrypt 100M time: [142.23 ms 143.17 ms 144.19 ms]
change: [+0.4705% +1.1593% +1.8840%] (p = 0.01 < 0.05)
Change within noise threshold.
decrypt 200M time: [286.54 ms 288.30 ms 289.82 ms]
change: [-1.3429% -0.2062% +0.7492%] (p = 0.73 > 0.05)
No change in performance detected.
In #243 (comment), 16B data is used for AES-GCM tests. I bumped the data size to 8 KiB, updated all crates to the latest version, and reran some of the tests.
@Schmid7k
Note that you usually do not need -Ctarget-feature when -Ctarget-cpu=native is specified. Compiler will use all available features for your CPU.
Also, curiously enough, -Ctarget-cpu=native often results in a worse codegen. For example, using only -Ctarget-feature results in 15-20% better throughput on my AMD Ryzen 7 2700x based PC compared to -Ctarget-cpu=native (0.49 vs 0.57 cpb).
I think OpenSSL Performance is an unfair comparison; as @tarcieri noted earlier in this thread OpenSSL has a dedicated person writing hand crafted assembly for different instruction sets. With Perl scripts to take away the pain of updating to CPU specific feature novelties, variations and new models. OpenSSL is now a fairly well funded project for FOSS standards. That person actually fixes more bugs in OpenSSL than he ever introduced as well. So is it a good idea to do the same with an unsafe { asm! { ... }} for a programming language which paradigms forbid general use of such hacks? I don't think so. You can still use a foreign function interface to access low-level OpenSSL cipher primitives if you need the optimized code speed in some application where it really matters (e.g. https://tests.reproducible-builds.org/debian/rb-pkg/unstable/amd64/rust-openssl.html)
I had more to say but GitHub swallowed my original comment draft so that's it for now.
Are there any plans on improving performance? It's not only slow when compared to openssl. In my benchmarks, the aes-gcm implementation is about 2x as slow as the sodiumoxide implementation. Unfortunately, sodiumoxide isn't maintained anymore.
I think we're bottlenecked on the trait design of universal-hash, which prevents data from flowing through SIMD registers and is instead loading and storing it in RAM instead.
Without that we can't take advantage of pipelining between AES-NI and (P)CLMUL(QDQ), which would give us an expected 2X speedup, as it were. I had an issue for that here, which we should probably reopen:
Another option would be to add architecture-specific low-level APIs to crates like aes/polyval and chacha20/poly1305 which operate in terms of platform-native SIMD buffers, sidestepping the current trait-based APIs.
If we can get things performing well that way, I think it could help inform the overall trait design for RustCrypto/traits#444.
2024 here - I'm seeing 5x slower CTR performance than Golang's standard library CTR implementation. In both of my test codebases, I'm using AES-256-CTR with 128-bit big endian encoding splitting the inputs into 4KB chunks and encrypting each chunk. On a 100 MB file filled with random data, my Go program encrypts it all in 146.5205ms, while Rust takes 630.505875ms. This comparison was done dozens of times on an M1 Pro MacBook and Go consistently outperforms Rust.
@httpjamesm can you please provide more information including code examples as well as the target architecture? The aes crate has multiple architecture-specific backends which target specific hardware features, so it's unhelpful to get a report that doesn't include that information.
It would also be helpful if you could reduce your test case to the AES block function in the case of CTR and see if you still experience the problem, as CTR itself is unlikely to add much overhead.
as tarcieri noted earlier in this thread OpenSSL has a dedicated person writing hand crafted assembly for different instruction sets. With Perl scripts to take away the pain of updating to CPU specific feature novelties, variations and new models.
Note that the Linux kernel just gained a hand-crafted assembly implementation of x86-64 AES-GCM that's far smaller than OpenSSL, just 8 kB of machine code, and performance on par with OpenSSL implementation. The assembly code is heavily commented as well. Mayhaps there is something to be learned from there: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b06affb1cb58
My thinking was not to use the source as is, but it could inform some ideas how do design a high-performance implementation in a reasonable amount of code.
But FWIW it's also cross-licensed, from the commit message:
To facilitate potential integration into other projects, I've dual-licensed aes-gcm-avx10-x86_64.S under Apache-2.0 OR BSD-2-Clause, the same as the recently added RISC-V crypto code.
I'll note again that while this issue has focused a lot on ASM implementations, I think the biggest problem (as I noted earlier) continues to be our scheduling of encryption/decryption and authentication, namely we perform these operations in sequence rather than leveraging ILP, which is tracked in RustCrypto/traits#444
@str4d has been doing a good job of tracking chacha20poly1305 performance over here: str4d/rage#57
We should probably open our own issue, though.
Dropping in an inline assembly implementation is definitely an option we can pursue for select targets, so long as it's feature/cfg gated. Ideally we could find a formally verified assembly implementation that performs better than what we have already.
Activity
tarcieri commentedon Dec 4, 2020
Presently you need to enable RUSTFLAGS as described here for optimum performance:
https://docs.rs/aes-gcm/0.8.0/aes_gcm/#performance-notes
We are working on and have partially implemented autodetection support for these CPU features which will eliminate the need to manually configure RUSTFLAGS and will be available in the next release.
kigawas commentedon Dec 4, 2020
Well, it was built with RUSTFLAGS.
Surprisingly the performance is approximately 50% in encryption and 30% in decryption compared to OpenSSL.
[-]Performance is much worse than OpenSSL[/-][+]Performance is worse than OpenSSL[/+]tarcieri commentedon Dec 4, 2020
I'm not sure that much of a difference deserves the qualifier "much".
We've presently been working on features like CPU feature autodetection (which are important) and haven't heavily invested in micro-optimization.
OpenSSL uses heavily optimized hand-written assembly implementations (in the case of AES-GCM, written by cryptography engineers at Intel), so reaching performance parity with those (especially in pure Rust) will be difficult.
[-]Performance is worse than OpenSSL[/-][+]aes-gcm: performance is worse than OpenSSL[/+]tarcieri commentedon Dec 4, 2020
If anyone would like to work on improving AES-GCM performance, #74 might be a good start
tarcieri commentedon Dec 8, 2020
Also note: for optimum performance, pass
Ctarget-cpu=native.This will significantly improve performance on Skylake, where LLVM will use the VPCLMULQDQ instruction for GHASH.
newpavlov commentedon Dec 8, 2020
In my experience
target-cpu=nativeoften results in a degraded performance (one possible explanation is CPU down-clocking due to the AVX2 instructions being used here and there), so I would be careful with it.kigawas commentedon Dec 9, 2020
I didn't see any statistically significant difference on iMac 2019, thanks anyway :)
LuoZijun commentedon Dec 21, 2020
@kigawas
The
x86_64platform,aes-gcmperformance is fast then OpenSSL.maybe you can share your bench code.
My bench code: LuoZijun/crypto-bench
Bench Result:
X86-64:
AArch64:
database64128 commentedon Jan 6, 2022
In #243 (comment), 16B data is used for AES-GCM tests. I bumped the data size to 8 KiB, updated all crates to the latest version, and reran some of the tests.
On i5-7400 (avx2):
On Intel(R) Xeon(R) Platinum 8272CL (avx512 w/o vaes, vpclmulqdq):
tarcieri commentedon Mar 31, 2022
@Schmid7k we already have
criterionbenchmarks that make use ofcriterion-cycles-per-bytehere:https://github.com/RustCrypto/AEADs/tree/master/benches
newpavlov commentedon Mar 31, 2022
@Schmid7k
Note that you usually do not need
-Ctarget-featurewhen-Ctarget-cpu=nativeis specified. Compiler will use all available features for your CPU.Also, curiously enough,
-Ctarget-cpu=nativeoften results in a worse codegen. For example, using only-Ctarget-featureresults in 15-20% better throughput on my AMD Ryzen 7 2700x based PC compared to-Ctarget-cpu=native(0.49 vs 0.57 cpb).AES-GCM should improve significantly when RustCrypto/traits#965 will land.
7 remaining items
azet commentedon Jul 5, 2022
hey Rustycrypto,
I think OpenSSL Performance is an unfair comparison; as @tarcieri noted earlier in this thread OpenSSL has a dedicated person writing hand crafted assembly for different instruction sets. With Perl scripts to take away the pain of updating to CPU specific feature novelties, variations and new models. OpenSSL is now a fairly well funded project for FOSS standards. That person actually fixes more bugs in OpenSSL than he ever introduced as well. So is it a good idea to do the same with an
unsafe { asm! { ... }}for a programming language which paradigms forbid general use of such hacks? I don't think so. You can still use a foreign function interface to access low-level OpenSSL cipher primitives if you need the optimized code speed in some application where it really matters (e.g. https://tests.reproducible-builds.org/debian/rb-pkg/unstable/amd64/rust-openssl.html)I had more to say but GitHub swallowed my original comment draft so that's it for now.
PS: I don't see OCB anywhere :P
Happy hacking,
azet
smessmer commentedon May 24, 2023
Are there any plans on improving performance? It's not only slow when compared to
openssl. In my benchmarks, theaes-gcmimplementation is about 2x as slow as thesodiumoxideimplementation. Unfortunately,sodiumoxideisn't maintained anymore.tarcieri commentedon May 24, 2023
I think we're bottlenecked on the trait design of
universal-hash, which prevents data from flowing through SIMD registers and is instead loading and storing it in RAM instead.Without that we can't take advantage of pipelining between AES-NI and (P)CLMUL(QDQ), which would give us an expected 2X speedup, as it were. I had an issue for that here, which we should probably reopen:
RustCrypto/traits#444
See also: #74
As I mentioned before in this issue, we could also include inline ASM implementations for certain platforms, gated under an
asmfeature.tarcieri commentedon May 24, 2023
Another option would be to add architecture-specific low-level APIs to crates like
aes/polyvalandchacha20/poly1305which operate in terms of platform-native SIMD buffers, sidestepping the current trait-based APIs.If we can get things performing well that way, I think it could help inform the overall trait design for RustCrypto/traits#444.
httpjamesm commentedon Jul 4, 2024
2024 here - I'm seeing 5x slower CTR performance than Golang's standard library CTR implementation. In both of my test codebases, I'm using AES-256-CTR with 128-bit big endian encoding splitting the inputs into 4KB chunks and encrypting each chunk. On a 100 MB file filled with random data, my Go program encrypts it all in 146.5205ms, while Rust takes 630.505875ms. This comparison was done dozens of times on an M1 Pro MacBook and Go consistently outperforms Rust.
tarcieri commentedon Jul 8, 2024
@httpjamesm can you please provide more information including code examples as well as the target architecture? The
aescrate has multiple architecture-specific backends which target specific hardware features, so it's unhelpful to get a report that doesn't include that information.It would also be helpful if you could reduce your test case to the AES block function in the case of CTR and see if you still experience the problem, as CTR itself is unlikely to add much overhead.
intgr commentedon Aug 1, 2024
Note that the Linux kernel just gained a hand-crafted assembly implementation of x86-64 AES-GCM that's far smaller than OpenSSL, just 8 kB of machine code, and performance on par with OpenSSL implementation. The assembly code is heavily commented as well. Mayhaps there is something to be learned from there: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b06affb1cb58
tarcieri commentedon Aug 1, 2024
Note there was a PR to add VAES support to the
aescrate here, but it was disappointingly closed by its author: RustCrypto/block-ciphers#396newpavlov commentedon Aug 2, 2024
@intgr
IIUC this assembly is licensed under GPL, so we can not use it in our crates.
intgr commentedon Aug 2, 2024
My thinking was not to use the source as is, but it could inform some ideas how do design a high-performance implementation in a reasonable amount of code.
But FWIW it's also cross-licensed, from the commit message:
tarcieri commentedon Jan 21, 2025
I'll note again that while this issue has focused a lot on ASM implementations, I think the biggest problem (as I noted earlier) continues to be our scheduling of encryption/decryption and authentication, namely we perform these operations in sequence rather than leveraging ILP, which is tracked in RustCrypto/traits#444
dignifiedquire commentedon Feb 22, 2025
another nice comparison for reference https://jbp.io/graviola/
elichai commentedon Feb 1, 2026
This is also true for chacha20-poly1305, even on macOS(simpler simd):
(encrypt/decrypt have similiar numbers),
FWIW AWS-LC/BoringSSL have nicer licenses and they also include assembly (I think it's even verified)
tarcieri commentedon Feb 1, 2026
@str4d has been doing a good job of tracking
chacha20poly1305performance over here: str4d/rage#57We should probably open our own issue, though.
Dropping in an inline assembly implementation is definitely an option we can pursue for select targets, so long as it's feature/cfg gated. Ideally we could find a formally verified assembly implementation that performs better than what we have already.
quic: seal/open packets with the stitched Aes128GcmFast (was RustCrypto)