// Times the BLS12-381 and tlock code of stage 3 (docs/PLAN_dart.md, // «Rendimiento»): decoding a point of G1 and of G2, one pairing, the // verification of a Quicknet round signature (hash to G1 and the pairing // check), the IBE decryption of a tlock stanza, the IBE encryption, and // steps 10 and 11 of the opening together. On the VM: // // dart run tool/bls12381_bench.dart // // and compiled to JavaScript, on Node.js, where dart2js reaches the random // generator through self: // // dart compile js -O2 -o bench.js tool/bls12381_bench.dart // node -e "globalThis.self = globalThis; require('./bench.js')" // // Each figure is the median of several runs after one to warm up. The // program reads no file, so that it runs on the web too. // ignore_for_file: avoid_print library; import 'package:datekeys/datekeys.dart' show fromHex; import 'package:datekeys/src/bls12381_curve.dart'; import 'package:datekeys/src/bls12381_pairing.dart'; import 'package:datekeys/src/ibe.dart'; import 'package:datekeys/src/release.dart'; import 'package:datekeys/src/tlock.dart'; // The pinned Quicknet profile, as testdata/vectors/profile_quicknet.json. final class _Quicknet implements PinnedProfile { @override String get id => 'datekeys:quicknet:v1'; @override String get scheme => quicknetScheme; @override final publicKey = fromHex( '83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b' '6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809' 'bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a', ); @override final chainHash = fromHex( '52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971', ); @override int get maxRound => 83903165811; } // The releases of rounds 1000 and 1001 (testdata/fixtures/time_only.json and // empty_payload.json). The runs alternate between them: the last release // verified is kept (release.dart), and verifying it again costs no pairing. final _signatures = { 1000: fromHex( 'b44679b9a59af2ec876b1a6b1ad52ea9b1615fc3982b19576350f93447cb1125e342b73a' '8dd2bacbe47e4b6b63ed5e39', ), 1001: fromHex( 'b33bf3667cbd5a82de3a24b4e0e9fe5513cc1a0e840368c6e31f5fcfa79bea03f73896b2' '5883abf2853d10337fb8fa41', ), }; double _median(List xs) => (xs..sort())[xs.length ~/ 2]; void _time(String name, int runs, void Function(int round) body) { body(1001); final ms = []; for (var i = 0; i < runs; i++) { final round = i.isEven ? 1000 : 1001; final sw = Stopwatch()..start(); body(round); ms.add(sw.elapsedMicroseconds / 1000); } print('${name.padRight(48)} ${_median(ms).toStringAsFixed(1)} ms'); } void main(List args) { final runs = args.isEmpty ? 7 : int.parse(args.first); final p = _Quicknet(); Release release(int round) => Release(round, _signatures[round]!); final sig = G1Point.decode(_signatures[1000]!)!; final key = G2Point.decode(p.publicKey)!; final message = fromHex('00112233445566778899aabbccddeeff'); final ct = { for (final round in [1000, 1001]) round: encryptOnG2(p.publicKey, roundIdentity(round), message), }; final stanza = { for (final round in [1000, 1001]) round: wrapTlockStanza(p, round, message), }; _time('decode a point of G1 (the signature)', runs, (round) { G1Point.decode(_signatures[round]!); }); _time('decode a point of G2 (U)', runs, (round) { G2Point.decode(ct[round]!.u); }); _time('one pairing', runs, (_) => pairing(sig, key)); // The pinned key is decoded once and kept (pinnedKey of release.dart): the // first verification pays for it. _time('verify a Quicknet round signature, key kept', runs, (round) { verifyRelease(p, round, release(round)); }); _time('the same, decoding the pinned key', runs, (round) { G2Point.decode(p.publicKey); verifyRelease(p, round, release(round)); }); _time('IBE decryption of a tlock stanza', runs, (round) { decryptOnG2(_signatures[round]!, ct[round]!); }); _time('IBE encryption', runs, (round) { encryptOnG2(p.publicKey, roundIdentity(round), message); }); // Steps 10 and 11 of the opening: the release verified, then the stanza // unwrapped, which verifies the same release again, as Go does. _time('steps 10 and 11: verify, then unwrap the stanza', runs, (round) { verifyRelease(p, round, release(round)); final (args, body) = stanza[round]!; unwrapTlockStanza(p, round, release(round), args, body); }); }