diff --git a/README.md b/README.md index 8679fde..5a02c7d 100644 --- a/README.md +++ b/README.md @@ -470,73 +470,40 @@ uint8array into encrypt / decrypt methods. Benchmark results on Apple M2 with node v22: ``` -encrypt (64B) -├─xsalsa20poly1305 x 485,908 ops/sec @ 2μs/op -├─chacha20poly1305 x 414,250 ops/sec @ 2μs/op -├─xchacha20poly1305 x 331,674 ops/sec @ 3μs/op -├─aes-256-gcm x 144,237 ops/sec @ 6μs/op -└─aes-256-gcm-siv x 121,373 ops/sec @ 8μs/op -encrypt (1KB) -├─xsalsa20poly1305 x 136,574 ops/sec @ 7μs/op -├─chacha20poly1305 x 136,017 ops/sec @ 7μs/op -├─xchacha20poly1305 x 126,008 ops/sec @ 7μs/op -├─aes-256-gcm x 40,149 ops/sec @ 24μs/op -└─aes-256-gcm-siv x 37,420 ops/sec @ 26μs/op -encrypt (8KB) -├─xsalsa20poly1305 x 22,517 ops/sec @ 44μs/op -├─chacha20poly1305 x 23,187 ops/sec @ 43μs/op -├─xchacha20poly1305 x 22,837 ops/sec @ 43μs/op -├─aes-256-gcm x 7,993 ops/sec @ 125μs/op -└─aes-256-gcm-siv x 7,836 ops/sec @ 127μs/op -encrypt (1MB) -├─xsalsa20poly1305 x 186 ops/sec @ 5ms/op -├─chacha20poly1305 x 191 ops/sec @ 5ms/op -├─xchacha20poly1305 x 191 ops/sec @ 5ms/op -├─aes-256-gcm x 71 ops/sec @ 14ms/op -└─aes-256-gcm-siv x 75 ops/sec @ 13ms/op -``` - -Unauthenticated encryption: +64B +xsalsa20poly1305 x 501,756 ops/sec @ 1μs/op +chacha20poly1305 x 428,082 ops/sec @ 2μs/op +xchacha20poly1305 x 343,170 ops/sec @ 2μs/op +aes-256-gcm x 147,492 ops/sec @ 6μs/op +aes-256-gcm-siv x 122,085 ops/sec @ 8μs/op +# Unauthenticated encryption +salsa20 x 1,288,659 ops/sec @ 776ns/op +xsalsa20 x 1,055,966 ops/sec @ 947ns/op +chacha20 x 1,506,024 ops/sec @ 664ns/op +xchacha20 x 1,064,962 ops/sec @ 939ns/op +chacha8 x 1,683,501 ops/sec @ 594ns/op +chacha12 x 1,628,664 ops/sec @ 614ns/op +aes-256-ecb x 775,193 ops/sec @ 1μs/op +aes-256-cbc x 738,552 ops/sec @ 1μs/op +aes-256-ctr x 737,463 ops/sec @ 1μs/op + +1MB +xsalsa20poly1305 x 205 ops/sec @ 4ms/op +chacha20poly1305 x 213 ops/sec @ 4ms/op +xchacha20poly1305 x 213 ops/sec @ 4ms/op +aes-256-gcm x 77 ops/sec @ 12ms/op +aes-256-gcm-siv x 81 ops/sec @ 12ms/op +# Unauthenticated encryption +salsa20 x 498 ops/sec @ 2ms/op +xsalsa20 x 493 ops/sec @ 2ms/op +chacha20 x 506 ops/sec @ 1ms/op +xchacha20 x 506 ops/sec @ 1ms/op +chacha8 x 956 ops/sec @ 1ms/op +chacha12 x 735 ops/sec @ 1ms/op +aes-256-ecb x 229 ops/sec @ 4ms/op +aes-256-cbc x 110 ops/sec @ 9ms/op +aes-256-ctr x 115 ops/sec @ 8ms/op -``` -encrypt (64B) -├─salsa x 1,221,001 ops/sec @ 819ns/op -├─chacha x 1,373,626 ops/sec @ 728ns/op -├─xsalsa x 1,019,367 ops/sec @ 981ns/op -└─xchacha x 1,019,367 ops/sec @ 981ns/op -encrypt (1KB) -├─salsa x 349,162 ops/sec @ 2μs/op -├─chacha x 372,717 ops/sec @ 2μs/op -├─xsalsa x 327,868 ops/sec @ 3μs/op -└─xchacha x 332,446 ops/sec @ 3μs/op -encrypt (8KB) -├─salsa x 55,178 ops/sec @ 18μs/op -├─chacha x 51,535 ops/sec @ 19μs/op -├─xsalsa x 54,274 ops/sec @ 18μs/op -└─xchacha x 55,645 ops/sec @ 17μs/op -encrypt (1MB) -├─salsa x 451 ops/sec @ 2ms/op -├─chacha x 464 ops/sec @ 2ms/op -├─xsalsa x 455 ops/sec @ 2ms/op -└─xchacha x 462 ops/sec @ 2ms/op - -AES -encrypt (64B) -├─ctr-256 x 679,347 ops/sec @ 1μs/op -├─cbc-256 x 699,300 ops/sec @ 1μs/op -└─ecb-256 x 717,875 ops/sec @ 1μs/op -encrypt (1KB) -├─ctr-256 x 93,423 ops/sec @ 10μs/op -├─cbc-256 x 95,721 ops/sec @ 10μs/op -└─ecb-256 x 154,726 ops/sec @ 6μs/op -encrypt (8KB) -├─ctr-256 x 12,908 ops/sec @ 77μs/op -├─cbc-256 x 13,411 ops/sec @ 74μs/op -└─ecb-256 x 22,681 ops/sec @ 44μs/op -encrypt (1MB) -├─ctr-256 x 105 ops/sec @ 9ms/op -├─cbc-256 x 108 ops/sec @ 9ms/op -└─ecb-256 x 181 ops/sec @ 5ms/op ``` Compare to other implementations: diff --git a/benchmark/README.md b/benchmark/README.md index be63408..0c74289 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -7,4 +7,4 @@ node ciphers.js # ChaCha, etc - all libs node ciphers.js noble # ChaCha, etc - only noble node aes.js # AES, SIV node poly.js # Poly1305 -``` \ No newline at end of file +``` diff --git a/benchmark/_utils.js b/benchmark/_utils.js index d3d836b..28d2fff 100644 --- a/benchmark/_utils.js +++ b/benchmark/_utils.js @@ -1,6 +1,11 @@ import { deepStrictEqual } from 'assert'; import { compare } from 'micro-bmark'; +export const onlyNoble = process.argv[2] === 'noble'; +export function buf(n) { + return new Uint8Array(n).fill(n % 251); +} + // type Buffers = ({size: string, samples: number, data: Uint8Array})[]; export async function crossValidate(buffers, ciphers) { // Verify that things we bench actually work @@ -64,10 +69,6 @@ export async function validateHashes(buffers, HASHES) { console.log('Libraries cross-validated against each other correctly'); } -export const onlyNoble = process.argv[2] === 'noble'; -export function buf(n) { - return new Uint8Array(n).fill(n); -} export async function benchmarkOnlyNoble(buffers, ciphers) { const nobleImpls = []; // chacha20_poly1305: { diff --git a/benchmark/noble.js b/benchmark/noble.js new file mode 100644 index 0000000..927b74b --- /dev/null +++ b/benchmark/noble.js @@ -0,0 +1,47 @@ +import { mark } from 'micro-bmark'; +import { buf } from './_utils.js'; +import { concatBytes } from '@noble/ciphers/utils'; +import { xsalsa20poly1305 } from '@noble/ciphers/salsa'; +import { xchacha20poly1305, chacha20poly1305 } from '@noble/ciphers/chacha'; +import { salsa20, xsalsa20 } from '@noble/ciphers/salsa'; +import { chacha20, xchacha20, chacha8, chacha12 } from '@noble/ciphers/chacha'; +import { ecb, ctr, cbc, gcm, siv } from '@noble/ciphers/aes'; + +const buffers = [ + // { size: '16B', samples: 1_500_000, data: buf(16) }, // common block size + { size: '32B', samples: 1_500_000, data: buf(32) }, + { size: '64B', samples: 1_000_000, data: buf(64) }, + // { size: '1KB', samples: 50_000, data: buf(1024) }, + // { size: '8KB', samples: 10_000, data: buf(1024 * 8) }, + { size: '1MB', samples: 100, data: buf(1024 * 1024) }, +]; + +async function main() { + const key = buf(32); + const nonce = buf(12); + const nonce8 = buf(8); + const nonce16 = buf(16); + const nonce24 = buf(24); + for (let i = 0; i < 100000; i++) xsalsa20poly1305(key, nonce24).encrypt(buf(64)); // warm-up + for (const { size, samples: i, data: buf } of buffers) { + console.log(size); + await mark('xsalsa20poly1305', i, () => xsalsa20poly1305(key, nonce24).encrypt(buf)); + await mark('chacha20poly1305', i, () => chacha20poly1305(key, nonce).encrypt(buf)); + await mark('xchacha20poly1305', i, () => xchacha20poly1305(key, nonce24).encrypt(buf)); + await mark('aes-256-gcm', i, () => gcm(key, nonce).encrypt(buf)); + await mark('aes-256-gcm-siv', i, () => siv(key, nonce).encrypt(buf)); + + console.log('# Unauthenticated encryption'); + await mark('salsa20', i, () => salsa20(key, nonce8, buf)); + await mark('xsalsa20', i, () => xsalsa20(key, nonce24, buf)); + await mark('chacha20', i, () => chacha20(key, nonce, buf)); + await mark('xchacha20', i, () => xchacha20(key, nonce24, buf)); + await mark('chacha8', i, () => chacha8(key, nonce, buf)); + await mark('chacha12', i, () => chacha12(key, nonce, buf)); + await mark('aes-256-ecb', i, () => ecb(key).encrypt(buf)); + await mark('aes-256-cbc', i, () => cbc(key, nonce16).encrypt(buf)); + await mark('aes-256-ctr', i, () => ctr(key, nonce16).encrypt(buf)); + console.log(); + } +} +main(); diff --git a/test/crosstest.test.js b/test/crosstest.test.js index 1b494a0..3d90d86 100644 --- a/test/crosstest.test.js +++ b/test/crosstest.test.js @@ -76,7 +76,7 @@ const nodeCipher = (name, pcks7 = true) => { }; function buf(n) { - return new Uint8Array(n).fill(n); + return new Uint8Array(n).fill(n % 251); } // TODO: re-use in benchmarks? // There is more ciphers, also 192 versions