| 1 | // Ascon-Hash256 (and Ascon-XOF128) benchmark compared to builtin |
| 2 | // crypto.sha256 (for sum256) and sha3.shake256 (for xof outputing 256-bits) |
| 3 | // |
| 4 | // This benchmark code was adapted from argon2 benchmark by @fleximus, the creator argon2 module. |
| 5 | // Credit tributed to @fleximus |
| 6 | // See https://gist.github.com/fleximus/db5b867a9a37da46340db61bdac6e696 |
| 7 | // |
| 8 | // Output |
| 9 | // ====== |
| 10 | // Sum and Xof 256-bits output performance comparison |
| 11 | // ============================================================ |
| 12 | // Iterations per test: 10000 |
| 13 | // -------------------------------------------------------------------------------------------------- |
| 14 | // Data Size | Ascon256 | Sha256 | Ratio 256 || AsconXof128 | Shake256 | Ratio (Xof) | |
| 15 | // -------------------------------------------------------------------------------------------------- |
| 16 | // 4 B | 24.00ms | 33.00ms | 0.73x || 24.00ms | 208.00ms | 0.12x | |
| 17 | // 6 B | 23.00ms | 53.00ms | 0.45x || 25.00ms | 287.00ms | 0.08x | |
| 18 | // 8 B | 35.00ms | 37.00ms | 0.95x || 26.00ms | 202.00ms | 0.18x | |
| 19 | // 16 B | 30.00ms | 37.00ms | 0.83x || 30.00ms | 205.00ms | 0.15x | |
| 20 | // 64 B | 55.00ms | 61.00ms | 0.89x || 53.00ms | 241.00ms | 0.23x | |
| 21 | // 75 B | 61.00ms | 57.00ms | 1.07x || 58.00ms | 182.00ms | 0.34x | |
| 22 | // 256 B | 154.00ms | 123.00ms | 1.25x || 144.00ms | 398.00ms | 0.39x | |
| 23 | // 512 B | 273.00ms | 216.00ms | 1.26x || 265.00ms | 779.00ms | 0.35x | |
| 24 | // 1025 B | 610.00ms | 401.00ms | 1.52x || 509.00ms | 1.37s | 0.45x | |
| 25 | // -------------------------------------------------------------------------------------------------- |
| 26 | // Total | 1.27s | 1.02s | 1.24x || 1.14s | 3.87s | 0.294x| |
| 27 | // -------------------------------------------------------------------------------------------------- |
| 28 | // |
| 29 | // Per-operation averages: |
| 30 | // Ascon256: 14108 ns per hash |
| 31 | // Sha256: 11360 ns per hash |
| 32 | // AsconXof128: 12648 ns per hash |
| 33 | // Shake256: 43036 ns per hash |
| 34 | // |
| 35 | module main |
| 36 | |
| 37 | import time |
| 38 | import crypto.sha3 |
| 39 | import crypto.sha256 |
| 40 | import x.crypto.ascon |
| 41 | |
| 42 | const benchmark_iterations = 10000 |
| 43 | |
| 44 | // We include more small size because, Ascon-Hash256 working with more smaller block size. |
| 45 | const test_data_sizes = [ |
| 46 | 4, // below Ascon-Hash256 block size |
| 47 | 6, // Still below Ascon-Hash256 block size |
| 48 | 8, // align with Ascon-Hash256 block size |
| 49 | 16, // Small data |
| 50 | 64, // Medium data |
| 51 | 75, // above 64-bytes block |
| 52 | 256, // Large data |
| 53 | 512, |
| 54 | 1025, |
| 55 | ] |
| 56 | |
| 57 | fn generate_test_data(size int) []u8 { |
| 58 | mut data := []u8{len: size} |
| 59 | for i in 0 .. size { |
| 60 | data[i] = u8(i % 256) |
| 61 | } |
| 62 | return data |
| 63 | } |
| 64 | |
| 65 | fn benchmark_ascon_sha256(data []u8, iterations int) time.Duration { |
| 66 | start := time.now() |
| 67 | for _ in 0 .. iterations { |
| 68 | _ := ascon.sum256(data) |
| 69 | } |
| 70 | return time.since(start) |
| 71 | } |
| 72 | |
| 73 | fn benchmark_sha256_sum256(data []u8, iterations int) time.Duration { |
| 74 | start := time.now() |
| 75 | for _ in 0 .. iterations { |
| 76 | _ := sha256.sum256(data) |
| 77 | } |
| 78 | return time.since(start) |
| 79 | } |
| 80 | |
| 81 | // for eXtendable output functions (XOF) |
| 82 | fn benchmark_ascon_xof128_32(data []u8, iterations int) time.Duration { |
| 83 | start := time.now() |
| 84 | for _ in 0 .. iterations { |
| 85 | _ := ascon.xof128(data, 32) or { panic(err) } |
| 86 | } |
| 87 | return time.since(start) |
| 88 | } |
| 89 | |
| 90 | fn benchmark_sha3_shake256(data []u8, iterations int) time.Duration { |
| 91 | start := time.now() |
| 92 | for _ in 0 .. iterations { |
| 93 | _ := sha3.shake256(data, 32) |
| 94 | } |
| 95 | return time.since(start) |
| 96 | } |
| 97 | |
| 98 | fn format_duration(d time.Duration) string { |
| 99 | if d.microseconds() < 1000 { |
| 100 | return '${d.microseconds():6}μs' |
| 101 | } else if d.milliseconds() < 1000 { |
| 102 | return '${f64(d.milliseconds()):6.2f}ms' |
| 103 | } else { |
| 104 | return '${f64(d.seconds()):6.2f}s' |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | const data_title = 'Data Size' |
| 109 | const ascon_sum256_title = 'Ascon256' |
| 110 | const sha256_title = 'Sha256' |
| 111 | const ascon_xof128_title = 'AsconXof128' |
| 112 | const sha3_shake256_title = 'Shake256' |
| 113 | const ratio_ascon256_w_sha256 = 'Ratio 256' |
| 114 | const ratio_asconxof128_w_shake256 = 'Ratio (Xof)' |
| 115 | |
| 116 | fn main() { |
| 117 | println('') |
| 118 | println('Sum and Xof 256-bits output performance comparison') |
| 119 | println('============================================================') |
| 120 | println('Iterations per test: ${benchmark_iterations}') |
| 121 | |
| 122 | println('${'-'.repeat(98)}') |
| 123 | println('${data_title:12} | ${ascon_sum256_title:10} | ${sha256_title:10} | ${ratio_ascon256_w_sha256:12} || ${ascon_xof128_title:10} | ${sha3_shake256_title:10} | ${ratio_asconxof128_w_shake256:12} |') |
| 124 | println('${'-'.repeat(98)}') |
| 125 | |
| 126 | mut total_ascon256 := time.Duration(0) |
| 127 | mut total_sha256 := time.Duration(0) |
| 128 | mut total_shake256 := time.Duration(0) |
| 129 | mut total_asconxof128 := time.Duration(0) |
| 130 | |
| 131 | for size in test_data_sizes { |
| 132 | test_data := generate_test_data(size) |
| 133 | |
| 134 | // Warm up |
| 135 | _ := ascon.sum256(test_data) |
| 136 | _ := sha256.sum256(test_data) |
| 137 | |
| 138 | _ := ascon.xof128(test_data, 32)! |
| 139 | _ := sha3.shake256(test_data, 32) |
| 140 | |
| 141 | // Benchmark Ascon-HASH256 |
| 142 | ascon256_time := benchmark_ascon_sha256(test_data, benchmark_iterations) |
| 143 | |
| 144 | // Benchmark Sha256 implementation |
| 145 | sha256_time := benchmark_sha256_sum256(test_data, benchmark_iterations) |
| 146 | |
| 147 | // Benchmark Sha3 shake256 implementation |
| 148 | shake256_time := benchmark_sha3_shake256(test_data, benchmark_iterations) |
| 149 | |
| 150 | // Benchmark AsconXof128 256-bits output |
| 151 | asconxof128_time := benchmark_ascon_xof128_32(test_data, benchmark_iterations) |
| 152 | |
| 153 | // Calculate ratio ascon256 / sha256 |
| 154 | ratio_ascon256_sha256 := f64(ascon256_time.nanoseconds()) / f64(sha256_time.nanoseconds()) |
| 155 | |
| 156 | // Calculate ratio asconxof128 / shake256 |
| 157 | ratio_asconxof128_shake256 := f64(asconxof128_time.nanoseconds()) / f64(shake256_time.nanoseconds()) |
| 158 | |
| 159 | ascon256_str := format_duration(ascon256_time) |
| 160 | sha256_str := format_duration(sha256_time) |
| 161 | asconxof128_str := format_duration(asconxof128_time) |
| 162 | shake256_str := format_duration(shake256_time) |
| 163 | |
| 164 | ratio_ascon256_sha256_str := '${ratio_ascon256_sha256:6.2f}x' |
| 165 | ratio_asconxof128_shake256_str := '${ratio_asconxof128_shake256:6.2f}x' |
| 166 | |
| 167 | println('${size:10} B | ${ascon256_str:10} | ${sha256_str:10} | ${ratio_ascon256_sha256_str:12} || ${asconxof128_str:11} | ${shake256_str:10} | ${ratio_asconxof128_shake256_str:12} |') |
| 168 | |
| 169 | total_ascon256 += ascon256_time |
| 170 | total_sha256 += sha256_time |
| 171 | |
| 172 | total_asconxof128 += asconxof128_time |
| 173 | total_shake256 += shake256_time |
| 174 | } |
| 175 | |
| 176 | println('${'-'.repeat(98)}') |
| 177 | |
| 178 | // Overall performance comparison |
| 179 | overall_ascon256_w_sha256_ratio := f64(total_ascon256.nanoseconds()) / f64(total_sha256.nanoseconds()) |
| 180 | overall_asconxof128_w_shake256_ratio := f64(total_asconxof128.nanoseconds()) / f64(total_shake256.nanoseconds()) |
| 181 | total_title := 'Total' |
| 182 | println('${total_title:12} | ${format_duration(total_ascon256):10} | ${format_duration(total_sha256):10} | ${overall_ascon256_w_sha256_ratio:11.2f}x || ${format_duration(total_asconxof128):11} | ${format_duration(total_shake256):10} | ${overall_asconxof128_w_shake256_ratio:12.2f}x|') |
| 183 | println('${'-'.repeat(98)}') |
| 184 | |
| 185 | println('') |
| 186 | println('Per-operation averages:') |
| 187 | avg_ascon256 := total_ascon256.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 188 | avg_sha256 := total_sha256.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 189 | avg_shake256 := total_shake256.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 190 | avg_asconxof128 := total_asconxof128.nanoseconds() / (benchmark_iterations * test_data_sizes.len) |
| 191 | |
| 192 | println(' Ascon256:\t ${avg_ascon256:8} ns per hash') |
| 193 | println(' Sha256:\t ${avg_sha256:8} ns per hash') |
| 194 | println(' AsconXof128:\t ${avg_asconxof128:8} ns per hash') |
| 195 | println(' Shake256:\t ${avg_shake256:8} ns per hash') |
| 196 | println('') |
| 197 | } |
| 198 | |