A day's, night's and heart chunk's ID was a UUID of version 5 of the person and the date, which the instance can hash for every date itself: each ID told it which days the band was worn. halkyon_keys' keyedRowId hashes the name under the account's X25519 secret key (BLAKE2b, a UUID of version 8), the same on every device of the account and unreadable without its keys; ContentCipher.rowId and TrainKeys.rowId hand it on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
55 lines
1.9 KiB
Dart
55 lines
1.9 KiB
Dart
import 'package:halkyon_keys/halkyon_keys.dart';
|
|
import 'package:sodium/sodium_sumo.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
Future<void> main() async {
|
|
final sodium = await SodiumSumoInit.init();
|
|
|
|
group('row IDs keyed by the account', () {
|
|
final account = AccountKeys.generate(sodium);
|
|
final secrets = (
|
|
encryption: account.encryption.secretKey.extractBytes(),
|
|
signing: account.signing.secretKey.extractBytes(),
|
|
);
|
|
|
|
test('every device of the account names a row alike: its keys, unlocked '
|
|
'anew, give the same ID', () {
|
|
final elsewhere = AccountKeys.fromSecretKeys(
|
|
sodium,
|
|
encryptionSecretKey: secrets.encryption,
|
|
signingSecretKey: secrets.signing,
|
|
);
|
|
expect(
|
|
keyedRowId(sodium, elsewhere, 'train/day/2026-10-30'),
|
|
keyedRowId(sodium, account, 'train/day/2026-10-30'),
|
|
);
|
|
});
|
|
|
|
test('another name, or the same name of another account, gives another '
|
|
'ID', () {
|
|
final other = AccountKeys.generate(sodium);
|
|
final id = keyedRowId(sodium, account, 'train/day/2026-10-30');
|
|
expect(keyedRowId(sodium, account, 'train/day/2026-10-31'), isNot(id));
|
|
expect(keyedRowId(sodium, account, 'train/night/2026-10-30'), isNot(id));
|
|
expect(keyedRowId(sodium, other, 'train/day/2026-10-30'), isNot(id));
|
|
});
|
|
|
|
test("the ID is a UUID of version 8, RFC 9562's for IDs of one's own "
|
|
'making, and not a name hashed in the open (version 5)', () {
|
|
final id = keyedRowId(sodium, account, 'train/day/2026-10-30');
|
|
expect(
|
|
id,
|
|
matches(
|
|
RegExp(
|
|
'^[0-9a-f]{8}-[0-9a-f]{4}-8[0-9a-f]{3}-[89ab][0-9a-f]{3}-'
|
|
r'[0-9a-f]{12}$',
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('a row without a name has no ID', () {
|
|
expect(() => keyedRowId(sodium, account, ''), throwsArgumentError);
|
|
});
|
|
});
|
|
}
|