diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 000000000..a7592500e --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,4 @@ +## 2024-03-01 - [Fast String Concatenation and Secure Random] + +**Learning:** String concatenation using `+=` inside loops is very slow for large iterations (O(N^2)). Using `StringBuffer` or allocating a `List` and using `String.fromCharCodes` is significantly faster (O(N)). Additionally, `Random.secure()` has a slight performance overhead but is essential for IDs to prevent predictability. Caching `Random.secure()` instances avoids initialization overhead. +**Action:** Replace `+=` string concatenation with `String.fromCharCodes` inside random string generators. Cache `Random.secure()` to save instantiation time. diff --git a/lib/abgabe/abgabe_client_lib/lib/src/models/auto_id_generator.dart b/lib/abgabe/abgabe_client_lib/lib/src/models/auto_id_generator.dart index 86c44fb09..ce3df0a63 100644 --- a/lib/abgabe/abgabe_client_lib/lib/src/models/auto_id_generator.dart +++ b/lib/abgabe/abgabe_client_lib/lib/src/models/auto_id_generator.dart @@ -16,17 +16,16 @@ class AutoIdGenerator { static const String alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - static final Random _random = Random(); + static final Random _secureRandom = Random.secure(); + static final _alphabetCodeUnits = alphabet.codeUnits; /// Automatically Generates a random new Id static String autoId() { - final stringBuffer = StringBuffer(); - const maxRandom = alphabet.length; - - for (var i = 0; i < idLength; ++i) { - stringBuffer.write(alphabet[_random.nextInt(maxRandom)]); - } - - return stringBuffer.toString(); + final codes = List.generate( + idLength, + (_) => + _alphabetCodeUnits[_secureRandom.nextInt(_alphabetCodeUnits.length)], + ); + return String.fromCharCodes(codes); } } diff --git a/lib/common_domain_models/lib/src/ids/src/id.dart b/lib/common_domain_models/lib/src/ids/src/id.dart index 022a684c5..e08cb94ad 100644 --- a/lib/common_domain_models/lib/src/ids/src/id.dart +++ b/lib/common_domain_models/lib/src/ids/src/id.dart @@ -8,6 +8,10 @@ import 'dart:math'; +final _secureRandom = Random.secure(); +const _chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; +final _charCodes = _chars.codeUnits; + class Id { final String value; @@ -21,15 +25,12 @@ class Id { /// Generates a new random [Id] with the given [length] using characters /// from a-z, A-Z and 0-9. static Id generate({int length = 20, Random? random}) { - random ??= Random(); - const chars = - 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - final id = - List.generate( - length, - (index) => chars[random!.nextInt(chars.length)], - ).join(); - return Id(id); + final rand = random ?? _secureRandom; + final codes = List.generate( + length, + (_) => _charCodes[rand.nextInt(_charCodes.length)], + ); + return Id(String.fromCharCodes(codes)); } @override diff --git a/lib/sharezone_utils/lib/src/random_string/random_string.dart b/lib/sharezone_utils/lib/src/random_string/random_string.dart index 2322868a4..1ebd9aca2 100644 --- a/lib/sharezone_utils/lib/src/random_string/random_string.dart +++ b/lib/sharezone_utils/lib/src/random_string/random_string.dart @@ -8,22 +8,23 @@ import 'dart:math'; +final _secureRandom = Random.secure(); +const _idChars = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; +final _idCharCodes = _idChars.codeUnits; + String randomString(int length) { - var rand = Random(); var codeUnits = List.generate(length, (index) { - return rand.nextInt(33) + 89; + return _secureRandom.nextInt(33) + 89; }); return String.fromCharCodes(codeUnits); } String randomIDString(int length) { - var rand = Random(); - const chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - String result = ""; - for (var i = 0; i < length; i++) { - result += chars[rand.nextInt(chars.length)]; - } - return result; + final codes = List.generate( + length, + (_) => _idCharCodes[_secureRandom.nextInt(_idCharCodes.length)], + ); + return String.fromCharCodes(codes); }