|
| 1 | +// Copyright (c) 2025 blackshirt. |
| 2 | +// Use of this source code is governed by an MIT license |
| 3 | +// that can be found in the LICENSE file. |
| 4 | +// |
| 5 | +// This file contains benchmarking code for standard AEAD_CHACHA20_POLY1305 encryption |
| 6 | +// and decryption compared to AEAD_CHACHA20_POLY1305 with PSIV construct. |
| 7 | +// |
| 8 | +// This output on my test. |
| 9 | +// Standard ChaCha20Poly1305 AEAD and PSIV construct output performance comparison |
| 10 | +// =============================================================================== |
| 11 | +// Iterations per test: 1000 |
| 12 | +// ------------------------------------------------------------------------------------------------------ |
| 13 | +// Data Size | Std | PSIV | Enc (std/psiv) || Std | PSIV | Dec (std/psiv)| |
| 14 | +// ------------------------------------------------------------------------------------------------------ |
| 15 | +// 6 B | 16.00ms | 19.00ms | 0.85x || 16.00ms | 19.00ms | 0.81x | |
| 16 | +// 8 B | 15.00ms | 19.00ms | 0.81x || 16.00ms | 18.00ms | 0.87x | |
| 17 | +// 12 B | 15.00ms | 20.00ms | 0.76x || 16.00ms | 20.00ms | 0.77x | |
| 18 | +// 16 B | 15.00ms | 21.00ms | 0.72x || 15.00ms | 19.00ms | 0.80x | |
| 19 | +// 64 B | 21.00ms | 25.00ms | 0.82x || 21.00ms | 26.00ms | 0.80x | |
| 20 | +// 75 B | 28.00ms | 35.00ms | 0.81x || 34.00ms | 44.00ms | 0.77x | |
| 21 | +// 256 B | 55.00ms | 59.00ms | 0.94x || 50.00ms | 63.00ms | 0.80x | |
| 22 | +// 1028 B | 174.00ms | 242.00ms | 0.72x || 178.00ms | 227.00ms | 0.78x | |
| 23 | +// 2049 B | 361.00ms | 522.00ms | 0.69x || 399.00ms | 558.00ms | 0.71x | |
| 24 | +// ------------------------------------------------------------------------------------------------------ |
| 25 | +// Total | 703.00ms | 965.00ms | 0.73x || 748.00ms | 1.00s | 0.75x| |
| 26 | +// ------------------------------------------------------------------------------------------------------ |
| 27 | +// |
| 28 | +// Per-operation averages: |
| 29 | +// Standard ChaCha20Poly1305 encrypt: 78209 ns per hash |
| 30 | +// ChaCha20Poly1305 PSIV encrypt: 107325 ns per hash |
| 31 | +// |
| 32 | +// Standard ChaCha20Poly1305 decrypt: 83151 ns per hash |
| 33 | +// ChaCha20Poly1305 PSIV decrypt: 111155 ns per hash |
| 34 | +module main |
| 35 | + |
| 36 | +import rand |
| 37 | +import time |
| 38 | +import x.crypto.chacha20poly1305 |
| 39 | + |
| 40 | +const benchmark_iterations = 1000 |
| 41 | + |
| 42 | +const test_data_sizes = [6, 8, 12, 16, 64, 75, 256, 1028, 2049] |
| 43 | + |
| 44 | +// standard AEAD_CHACHA20_POLY1305 encryption |
| 45 | +fn benchmark_aead_std_encrypt(msg []u8, key []u8, nonce []u8, ad []u8, iterations int) time.Duration { |
| 46 | + start := time.now() |
| 47 | + for _ in 0 .. iterations { |
| 48 | + _ := chacha20poly1305.encrypt(msg, key, nonce, ad) or { panic(err) } |
| 49 | + } |
| 50 | + return time.since(start) |
| 51 | +} |
| 52 | + |
| 53 | +// standard AEAD_CHACHA20_POLY1305 decryption |
| 54 | +fn benchmark_aead_std_decrypt(data []u8, key []u8, nonce []u8, ad []u8, iterations int) time.Duration { |
| 55 | + start := time.now() |
| 56 | + for _ in 0 .. iterations { |
| 57 | + _ := chacha20poly1305.decrypt(data, key, nonce, ad) or { panic(err) } |
| 58 | + } |
| 59 | + return time.since(start) |
| 60 | +} |
| 61 | + |
| 62 | +// psiv AEAD_CHACHA20_POLY1305 encryption |
| 63 | +fn benchmark_aead_psiv_encrypt(msg []u8, key []u8, nonce []u8, ad []u8, iterations int) time.Duration { |
| 64 | + start := time.now() |
| 65 | + for _ in 0 .. iterations { |
| 66 | + _ := chacha20poly1305.psiv_encrypt(msg, key, nonce, ad) or { panic(err) } |
| 67 | + } |
| 68 | + return time.since(start) |
| 69 | +} |
| 70 | + |
| 71 | +// psiv AEAD_CHACHA20_POLY1305 decryption |
| 72 | +fn benchmark_aead_psiv_decrypt(data []u8, key []u8, nonce []u8, ad []u8, iterations int) time.Duration { |
| 73 | + start := time.now() |
| 74 | + for _ in 0 .. iterations { |
| 75 | + _ := chacha20poly1305.psiv_decrypt(data, key, nonce, ad) or { panic(err) } |
| 76 | + } |
| 77 | + return time.since(start) |
| 78 | +} |
| 79 | + |
| 80 | +fn format_duration(d time.Duration) string { |
| 81 | + if d.microseconds() < 1000 { |
| 82 | + return '${d.microseconds():6}μs' |
| 83 | + } else if d.milliseconds() < 1000 { |
| 84 | + return '${f64(d.milliseconds()):6.2f}ms' |
| 85 | + } else { |
| 86 | + return '${f64(d.seconds()):6.2f}s' |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +const data_title = 'Data Size' |
| 91 | +const aead_std_enc = 'Std' |
| 92 | +const aead_psiv_enc = 'PSIV' |
| 93 | +const aead_std_dec = 'Std' |
| 94 | +const aead_psiv_dec = 'PSIV' |
| 95 | +const ratio_std_psiv_enc_title = 'Enc (std/psiv)' |
| 96 | +const ratio_std_psiv_dec_title = 'Dec (std/psiv)' |
| 97 | + |
| 98 | +fn main() { |
| 99 | + println('Standard ChaCha20Poly1305 AEAD and PSIV construct output performance comparison') |
| 100 | + println('===============================================================================') |
| 101 | + println('Iterations per test: ${benchmark_iterations}') |
| 102 | + |
| 103 | + println('${'-'.repeat(102)}') |
| 104 | + println('${data_title:12} | ${aead_std_enc:10} | ${aead_psiv_enc:10} | ${ratio_std_psiv_enc_title:12} || ${aead_std_dec:10} | ${aead_psiv_dec:12} | ${ratio_std_psiv_dec_title:12}|') |
| 105 | + println('${'-'.repeat(102)}') |
| 106 | + |
| 107 | + mut total_std_encrypt := time.Duration(0) |
| 108 | + mut total_std_decrypt := time.Duration(0) |
| 109 | + mut total_psiv_encrypt := time.Duration(0) |
| 110 | + mut total_psiv_decrypt := time.Duration(0) |
| 111 | + |
| 112 | + key := rand.bytes(32)! |
| 113 | + nonce := rand.bytes(12)! |
| 114 | + for size in test_data_sizes { |
| 115 | + ad := rand.bytes(size)! |
| 116 | + test_msg := rand.bytes(size)! |
| 117 | + |
| 118 | + // Warm up |
| 119 | + out0 := chacha20poly1305.encrypt(test_msg, key, nonce, ad)! |
| 120 | + _ := chacha20poly1305.decrypt(out0, key, nonce, ad)! |
| 121 | + |
| 122 | + out1 := chacha20poly1305.psiv_encrypt(test_msg, key, nonce, ad)! |
| 123 | + _ := chacha20poly1305.psiv_decrypt(out1, key, nonce, ad)! |
| 124 | + |
| 125 | + // Benchmark Standard AEAD_CHACHA20_POLY1305 encryption |
| 126 | + std_encrypt_time := benchmark_aead_std_encrypt(test_msg, key, nonce, ad, benchmark_iterations) |
| 127 | + |
| 128 | + // Benchmark Standard AEAD_CHACHA20_POLY1305 decryption |
| 129 | + std_decrypt_time := benchmark_aead_std_decrypt(out0, key, nonce, ad, benchmark_iterations) |
| 130 | + |
| 131 | + // Benchmark AEAD_CHACHA20_POLY1305 PSIV encryption |
| 132 | + psiv_encrypt_time := benchmark_aead_psiv_encrypt(test_msg, key, nonce, ad, benchmark_iterations) |
| 133 | + |
| 134 | + // Benchmark AEAD_CHACHA20_POLY1305 PSIV decryption |
| 135 | + psiv_decrypt_time := benchmark_aead_psiv_decrypt(out1, key, nonce, ad, benchmark_iterations) |
| 136 | + |
| 137 | + // Calculate ratio Standard/PSIV encryption |
| 138 | + ratio_std_psiv_encrypt := f64(std_encrypt_time.nanoseconds()) / f64(psiv_encrypt_time.nanoseconds()) |
| 139 | + |
| 140 | + // Calculate ratio Standard/PSIV decryption |
| 141 | + ratio_std_psiv_decrypt := f64(std_decrypt_time.nanoseconds()) / f64(psiv_decrypt_time.nanoseconds()) |
| 142 | + |
| 143 | + stdencrypt_str := format_duration(std_encrypt_time) |
| 144 | + stddecrypt_str := format_duration(std_decrypt_time) |
| 145 | + psivencrypt_str := format_duration(psiv_encrypt_time) |
| 146 | + psivdecrypt_str := format_duration(psiv_decrypt_time) |
| 147 | + |
| 148 | + ratio_std_psiv_encrypt_str := '${ratio_std_psiv_encrypt:6.2f}x' |
| 149 | + ratio_std_psiv_decrypt_str := '${ratio_std_psiv_decrypt:6.2f}x' |
| 150 | + |
| 151 | + println('${size:10} B | ${stdencrypt_str:10} | ${psivencrypt_str:10} | ${ratio_std_psiv_encrypt_str:14} || ${stddecrypt_str:10} | ${psivdecrypt_str:11} | ${ratio_std_psiv_decrypt_str:12} |') |
| 152 | + |
| 153 | + total_std_encrypt += std_encrypt_time |
| 154 | + total_std_decrypt += std_decrypt_time |
| 155 | + total_psiv_encrypt += psiv_encrypt_time |
| 156 | + total_psiv_decrypt += psiv_decrypt_time |
| 157 | + } |
| 158 | + |
| 159 | + println('${'-'.repeat(102)}') |
| 160 | + |
| 161 | + // Overall performance comparison |
| 162 | + overall_std_psiv_encrypt_ratio := f64(total_std_encrypt.nanoseconds()) / f64(total_psiv_encrypt.nanoseconds()) |
| 163 | + overall_std_psiv_decrypt_ratio := f64(total_std_decrypt.nanoseconds()) / f64(total_psiv_decrypt.nanoseconds()) |
| 164 | + |
| 165 | + total_title := 'Total' |
| 166 | + println('${total_title:12} | ${format_duration(total_std_encrypt):10} | ${format_duration(total_psiv_encrypt):10} | ${overall_std_psiv_encrypt_ratio:13.2f}x || ${format_duration(total_std_decrypt):10} | ${format_duration(total_psiv_decrypt):12} | ${overall_std_psiv_decrypt_ratio:12.2f}x|') |
| 167 | + println('${'-'.repeat(102)}') |
| 168 | + |
| 169 | + println('') |
| 170 | + println('Per-operation averages:') |
| 171 | + avg_std_encrypt := total_std_encrypt.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 172 | + avg_std_decrypt := total_std_decrypt.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 173 | + avg_psiv_encrypt := total_psiv_encrypt.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 174 | + avg_psiv_decrypt := total_psiv_decrypt.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 175 | + |
| 176 | + println(' Standard ChaCha20Poly1305 encrypt:\t ${avg_std_encrypt:8} ns per hash') |
| 177 | + println(' ChaCha20Poly1305 PSIV encrypt:\t ${avg_psiv_encrypt:8} ns per hash') |
| 178 | + println('') |
| 179 | + println(' Standard ChaCha20Poly1305 decrypt:\t ${avg_std_decrypt:8} ns per hash') |
| 180 | + println(' ChaCha20Poly1305 PSIV decrypt:\t ${avg_psiv_decrypt:8} ns per hash') |
| 181 | + println('') |
| 182 | +} |
0 commit comments