-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Use HashSet/SearchValues when known OID list is long #117849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR optimizes OID lookup performance by replacing Array.IndexOf with more efficient lookup mechanisms when dealing with long lists of known OIDs. The change introduces a new IStringLookup interface with implementations using SearchValues<string> for .NET 9+ and HashSet<string> for earlier versions, while maintaining StringLookupArray for short lists.
Key changes:
- Introduces
IStringLookupinterface and optimized implementations for string lookups - Updates cryptographic classes to use the new lookup mechanism for OID validation
- Conditionally uses
SearchValuesorHashSetbased on target framework for better performance
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| KeyFormatHelper.cs | Adds IStringLookup interface and implementations, updates method signatures to use the interface |
| KeyFormatHelper.Encrypted.cs | Updates method signatures to accept IStringLookup instead of string arrays |
| SlhDsa.cs | Replaces string array with StringLookup for 12 known OIDs |
| CompositeMLDsa.cs | Replaces string array with StringLookup for 18 known OIDs |
| ECAlgorithm.cs | Replaces string array with StringLookupArray for single OID |
| RSAKeyFormatHelper.cs | Replaces string array with StringLookupArray for single OID |
| MLKem.cs | Replaces string array with StringLookupArray for 3 OIDs |
| MLDsa.cs | Replaces string array with StringLookupArray for 3 OIDs |
| EccKeyFormatHelper.cs | Replaces string array with StringLookupArray for single OID |
| DSAKeyFormatHelper.cs | Replaces string array with StringLookupArray for single OID |
|
|
||
| internal sealed class StringLookupArray(string[] backingArray) : IStringLookup | ||
| { | ||
| public bool Contains(string value) => Array.IndexOf(backingArray, value) >= 0; |
Copilot
AI
Jul 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The StringLookupArray class stores the backing array but doesn't make a defensive copy. Consider making a copy of the input array to prevent external modifications that could affect lookup behavior.
| public bool Contains(string value) => Array.IndexOf(backingArray, value) >= 0; | |
| private readonly string[] _backingArray = (string[])backingArray.Clone(); | |
| public bool Contains(string value) => Array.IndexOf(_backingArray, value) >= 0; |
|
Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones |
|
Are there any benchmarks showing this is a worthwhile change? In the grand scheme of things, the OID lookups are done during PKCS#8 and SPKI import, so I would generally expect these to be only a small fraction of the actual key processing. |
| internal sealed class StringLookup(SearchValues<string> backingSearchValues) : IStringLookup | ||
| { | ||
| public bool Contains(string value) => backingSearchValues.Contains(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Despite the name, SearchValues is not beneficial in this case.
SearchValues<string>.Contains(string) is currently backed by a HashSet<string>.Contains(string).
The only searches this is being used for are setOfValues.Contains(string), this is what HashSet/FrozenSet excel at.
You'd want to use SearchValues if you were looking for substrings within a text, i.e. someText.ContainsAny(setOfValues).
I haven't run benchmarks but I expect the same. Regardless of perf, I think we should still get rid of the list for SLH-DSA and Composite ML-DSA and use |
bartonjs
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like the kind of change that feels like a perf win, but is actually a loss. N isn't very big here, and the affected methods run very few times in a real world program.
The comment suggesting that we stop using a duplicate list and just use an existing lookup function sounds reasonable; but is not a priority unless the change itself is trivially small.
|
Closing since there's no significant perf benefit. |
When the list of OIDs is long (SLH-DSA and Composite ML-DSA), use a more efficient lookup instead of
Array.IndexOf.