You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dateKeys-dart/tool/cms_bench.dart

121 lines
4.1 KiB

// Times the CMS reader of datekeys-dart, stage 5a, on the VM and compiled
// to JavaScript: the verification of one ECDSA signature on each curve and
// of one RSA signature of each size and scheme, the reading of a
// certificate, and a whole signature and a whole token read and checked. It
// reads no file: the cases are those of test/vectors/cms_vectors.g.dart.
//
// dart run tool/cms_bench.dart
//
// dart compile js -O2 -o cms_bench.js tool/cms_bench.dart
// node cms_bench.js
//
// ignore_for_file: avoid_print
import 'dart:convert';
import 'dart:typed_data';
import 'package:datekeys/src/bytes.dart';
import 'package:datekeys/src/cms.dart';
import 'package:datekeys/src/ecdsa.dart';
import 'package:datekeys/src/nist_curves.dart';
import 'package:datekeys/src/rsa.dart';
import '../test/vectors/cms_vectors.g.dart';
typedef Json = Map<String, Object?>;
List<Json> _cases(String json, String section) =>
((jsonDecode(json) as Json)[section]! as List).cast<Json>();
Json _named(String json, String section, String name) =>
_cases(json, section).firstWhere((c) => c['name'] == name);
Uint8List _hex(Object? v) => fromHex(v! as String);
/// The mean time of [f] in milliseconds, over at least [minRuns] runs and
/// about [budgetMs] milliseconds, after one run to warm up.
double time(void Function() f, {int minRuns = 3, int budgetMs = 2000}) {
f();
final sw = Stopwatch()..start();
var runs = 0;
while (runs < minRuns || sw.elapsedMilliseconds < budgetMs) {
f();
runs++;
}
return sw.elapsedMicroseconds / 1000 / runs;
}
String ms(double v) => '${v.toStringAsFixed(v < 10 ? 2 : 0)} ms';
void main() {
final curves = {'P-256': p256, 'P-384': p384, 'P-521': p521};
final keys = _cases(cmsEcdsaJson, 'keys');
for (final (curve, hash) in const [
('P-256', 'SHA-256'),
('P-384', 'SHA-384'),
('P-521', 'SHA-512'),
]) {
final c = _cases(cmsEcdsaJson, 'verify').firstWhere(
(c) => (c['name']! as String).startsWith('$curve, valid over $hash, '),
);
final k = keys[c['key']! as int];
final point = decodeUncompressed(curves[curve]!, _hex(k['point']))!;
final h = _hex(c['hash']);
final sig = _hex(c['sig']);
if (!verifyEcdsaAsn1(point, h, sig)) throw StateError('not valid');
print(
'ECDSA $curve, $hash, one verification: '
'${ms(time(() => verifyEcdsaAsn1(point, h, sig)))}',
);
}
final rsaKeys = _cases(cmsRsaJson, 'keys');
for (final c in _cases(cmsRsaJson, 'valid')) {
final k = rsaKeys[c['key']! as int];
if (k['e'] != 65537) continue;
final key = RsaPublicKey(
BigInt.parse(k['n']! as String, radix: 16),
k['e']! as int,
);
final digest = _hex(c['digest']);
final sig = _hex(c['sig']);
bool verify() => c['scheme'] == 'pss'
? verifyPss(key, Sha2.sha256, digest, sig)
: verifyPkcs1v15(key, Sha2.sha256, digest, sig);
if (!verify()) throw StateError('not valid');
print('RSA ${c['name']}, one verification: ${ms(time(verify))}');
}
for (final name in const ['field by field', 'rsa']) {
final der = _hex(_named(cmsCertsJson, 'bases', name)['der']);
print(
'parseCert, the certificate "$name" (${der.length} bytes): '
'${ms(time(() => parseCert(der).holder))}',
);
}
final message = _hex((jsonDecode(cmsMutationsJson) as Json)['message']);
for (final name in const ['sealed', 'co-signature']) {
final der = _hex(_named(cmsMutationsJson, 'signature_bases', name)['der']);
void check() {
for (final s in parseSignature(der).signers) {
if (s.check(message) != CmsResult.valid) throw StateError('invalid');
}
}
print(
'parseSignature and check, "$name" (${der.length} bytes): '
'${ms(time(check))}',
);
}
final subject = _hex((jsonDecode(cmsMutationsJson) as Json)['subject']);
final token = _hex(_named(cmsMutationsJson, 'token_bases', 'ecdsa')['der']);
void checkToken() {
if (!parseToken(token).check(subject)) throw StateError('invalid');
}
print(
'parseToken and check, ECDSA P-256 (${token.length} bytes): '
'${ms(time(checkToken))}',
);
}

Powered by TurnKey Linux.