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/test/securitycms_vm_test.dart

197 lines
6.9 KiB

// The verdicts of a signature of alg 2 and of a seal of seal_type 2 against
// Go, on the VM:
//
// - every case of testdata/vectors/security_cms.json, frozen by the Go
// reference at the draft v0.12, read in its context as TestCMSVectors of
// Go reads it, with its verdicts, the result of each signer, the authority
// and t of a valid seal, and its lines, byte for byte;
// - every case of test/vectors/securitycms_vectors.json, which
// tool/security_go_vectors.go makes and evaluates with package capsule of
// the reference: signers of every result, required and foreign, the
// validity of a certificate at the time of its seal, t plus the accuracy
// against the round time at the nanosecond, a seal of each kind beside a
// signature of each kind, and mutations;
// - and the part of both that securitycms_vectors.g.dart holds for the
// tests compiled to JavaScript, which must be that of the files.
@TestOn('vm')
library;
import 'dart:convert';
import 'dart:io';
import 'package:datekeys/datekeys.dart';
import 'package:test/test.dart';
import 'open_vectors_support.dart';
import 'security_support.dart';
import 'securitycms_support.dart';
import 'vectors/securitycms_vectors.g.dart';
Json readJson(String path) => jsonDecode(File(path).readAsStringSync()) as Json;
void main() {
group('security_cms.json', () {
final f = readJson('testdata/vectors/security_cms.json');
final cases = (f['cases']! as List).cast<Json>();
test('has the 135 cases of its README, which reach every verdict but X '
'and F3', () {
expect(f['spec'], specVersion);
expect(f['description'], contains('v0.12'));
expect(cases, hasLength(135));
expect({for (final c in cases) c['name']}, hasLength(135));
final reached = {
for (final c in cases) ...[c['signature'], c['seal']],
};
expect(reached, {
'F0', 'F1', 'F2', 'F4', 'F5', 'F6', //
'S0', 'S1', 'S2', 'S3', 'S4', 'S5',
});
// Every result of a signer, and a foreign one.
final results = {
for (final c in cases)
for (final s in (c['signers'] as List? ?? const []).cast<Json>())
s['result'],
};
expect(results, {for (final r in SignerResult.values) r.code});
expect(cases.where((c) => c['foreign_signers'] != null), isNotEmpty);
});
for (final c in cases) {
test(str(c, 'name'), () {
expect(cmsVectorDifferences(c), isEmpty);
});
}
});
group('securitycms_vectors.json', () {
final f = readJson('test/vectors/securitycms_vectors.json');
final cases = (f['cases']! as List).cast<Json>();
final chunks = chunksOf(f);
final bases = basesOf(f, chunks);
final contexts = contextsOf(f);
final texts = (f['texts']! as List).cast<String>();
test('is of this spec, from its generator, with every verdict and every '
'result of a signer, required and foreign', () {
expect(f['spec'], specVersion);
expect(f['generator'], 'tool/security_go_vectors.go');
expect(cases, hasLength(greaterThan(700)));
final verdicts = {
for (final c in cases) ...[c['signature'], c['seal']],
};
expect(verdicts, containsAll(<String>['F0', 'F1', 'F2', 'F4', 'F5']));
expect(verdicts, containsAll(<String>['F6', 'S0', 'S1', 'S2', 'S3']));
expect(verdicts, containsAll(<String>['S4', 'S5']));
Set<Object?> resultsOf(String list) => {
for (final c in cases)
if (c['detail'] case final Json d)
for (final s in (d[list]! as List).cast<Json>()) s['result'],
};
final all = {for (final r in SignerResult.values) r.code};
expect(resultsOf('signers'), all);
expect(resultsOf('foreign'), all.difference({'absent'}));
// A seal before the round time and one that is not, for a signer
// and for key 3, and Go's zero time, which gives no earliest seal.
final befores = {
for (final c in cases)
if (c['detail'] case final Json d)
for (final s in (d['signers']! as List).cast<Json>()) s['before'],
};
expect(befores, {true, false});
expect(
cases.where(
(c) =>
c['seal'] == 'S4' &&
c['sealed_at'] == null &&
c['detail'] != null,
),
isNotEmpty,
);
expect(contexts.where((c) => c.roundTime == null), isNotEmpty);
});
test('every case, with the verdicts, the lines, the detail and the '
'earliest seal of Go', () {
for (final c in cases) {
final area = cmsAreaOf(c, chunks, bases);
expect(
evaluateDifferences(c, area, contexts, texts),
isEmpty,
reason: c['name'] as String? ?? canonical(c),
);
}
});
test('securitycms_vectors.g.dart holds a part of it', () {
final part = jsonDecode(securityCmsVectorsJson) as Json;
for (final k in ['spec', 'generator', 'contexts', 'texts']) {
expect(canonical(part[k]), canonical(f[k]), reason: k);
}
expect(
[for (final b in basesOf(part, const [])) toHex(b)],
[for (final b in bases) toHex(b)],
);
// Each case of the part is one of the file, in the same order, with
// the same area.
String key(Json c) => canonical({
for (final e in c.entries)
if (e.key != 'pieces' && e.key != 'hex') e.key: e.value,
});
final some = (part['cases']! as List).cast<Json>();
expect(some, hasLength(greaterThan(40)));
var at = 0;
for (final c in some) {
while (at < cases.length && key(cases[at]) != key(c)) {
at++;
}
expect(at, lessThan(cases.length), reason: key(c));
expect(
cmsAreaOf(c, const [], bases),
cmsAreaOf(cases[at], chunks, bases),
reason: key(c),
);
}
});
});
test('the fixtures of securitycms_vectors.g.dart are those of testdata/, '
'with what their records say', () {
final fixtures =
((jsonDecode(securityCmsFixturesJson) as Json)['fixtures']! as List)
.cast<Json>();
expect(
[for (final x in fixtures) x['name']],
['format3_signed_cms', 'format3_sealed'],
);
for (final x in fixtures) {
final name = str(x, 'name');
final r = readJson('testdata/fixtures/$name.json');
expect(
x['dkc'],
toHex(File('testdata/fixtures/${r['file']}').readAsBytesSync()),
reason: name,
);
for (final k in ['release', 'unlock_at', 'verdicts']) {
expect(canonical(x[k]), canonical(r[k]), reason: '$name: $k');
}
final sig = r['signature'] as Json?;
expect(
canonical(x['signer_results']),
canonical(sig?['signer_results']),
reason: name,
);
final seal = r['seal'] as Json?;
expect(
canonical(x['seal']),
canonical(
seal == null
? null
: {'holder': seal['holder'], 'time': seal['time']},
),
reason: name,
);
}
});
}

Powered by TurnKey Linux.