From ecc11be74dcc5bea76bac97a18a1e1ad7acc6703 Mon Sep 17 00:00:00 2001 From: dev Date: Tue, 6 Oct 2026 13:16:56 +0200 Subject: [PATCH] Stage 7b: the benchmark of the author keys and the sealing tool/authorkey_bench.dart times on the VM and compiled to JavaScript the generation of an author key, its Ed25519 signature of 99 bytes and of 1 MiB, the strict verification for comparison, its file encrypted with scrypt of logN 16 and read again, sealLocator for round 1000 and newEnvelope of a .dkc of 1 MiB. Co-Authored-By: Claude Opus 5.5 --- tool/authorkey_bench.dart | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 tool/authorkey_bench.dart diff --git a/tool/authorkey_bench.dart b/tool/authorkey_bench.dart new file mode 100644 index 0000000..90c4a92 --- /dev/null +++ b/tool/authorkey_bench.dart @@ -0,0 +1,77 @@ +// Times stage 7b of datekeys-dart on the VM and compiled to JavaScript: an +// author key, generated, its Ed25519 signature of AUTHOR_MESSAGE (99 bytes) +// and of 1 MiB, its file encrypted with scrypt of logN 16 and read again; +// and the sealing of a locator of round 1000 and the envelope of a .dkc of +// 1 MiB. Each is the median of a few runs. The random values come from the +// CSPRNG of the platform, as in production. +// +// dart run tool/authorkey_bench.dart +// +// dart compile js -O2 -o authorkey_bench.js tool/authorkey_bench.dart +// node -e "globalThis.self = globalThis; require('./authorkey_bench.js')" +// +// ignore_for_file: avoid_print +import 'dart:typed_data'; + +import 'package:datekeys/datekeys.dart' show quicknet; +import 'package:datekeys/src/authorkey.dart'; +import 'package:datekeys/src/curve25519.dart' show verifyStrict; +import 'package:datekeys/src/locator.dart'; +import 'package:datekeys/src/locator_seal.dart'; + +const isWeb = identical(0, 0.0); + +double median(List xs) => (xs..sort())[xs.length ~/ 2]; + +/// The median time of [f], in milliseconds, over [runs] runs. +double time(int runs, void Function() f) { + final times = []; + for (var i = 0; i < runs; i++) { + final sw = Stopwatch()..start(); + f(); + times.add(sw.elapsedMicroseconds / 1000); + } + return median(times); +} + +String ms(double t) => t < 10 ? t.toStringAsFixed(2) : t.toStringAsFixed(0); + +void main() { + print('stage 7b, ${isWeb ? 'Node.js' : 'VM'}'); + final key = AuthorKey.generate(); + final msg = Uint8List(99); + final big = Uint8List(1 << 20); + // Warm up. + for (var i = 0; i < 20; i++) { + key.sign(msg); + } + print('AuthorKey.generate: ${ms(time(15, AuthorKey.generate))} ms'); + print('Ed25519 sign, 99 bytes: ${ms(time(31, () => key.sign(msg)))} ms'); + final sig = key.sign(msg); + print( + 'Ed25519 verifyStrict, 99 bytes: ' + '${ms(time(31, () => verifyStrict(key.publicKey, msg, sig)))} ms', + ); + print('Ed25519 sign, 1 MiB: ${ms(time(7, () => key.sign(big)))} ms'); + late Uint8List file; + print( + 'encryptAuthorKey, scrypt logN 16: ' + '${ms(time(5, () => file = encryptAuthorKey(key, 'a passphrase')))} ms', + ); + print( + 'readAuthorKey, scrypt logN 16: ' + '${ms(time(5, () => readAuthorKey(file, passphrase: 'a passphrase')))} ms', + ); + final e = newEnvelope(Uint8List(100)); + final loc = e.locator.withAddresses([ + LocatorAddress('https://example.com/rest'), + ]); + print( + 'sealLocator, round 1000: ' + '${ms(time(5, () => sealLocator(quicknet(), 1000, loc)))} ms', + ); + print( + 'newEnvelope, a .dkc of 1 MiB: ' + '${ms(time(5, () => newEnvelope(big)))} ms', + ); +}