@@ -44,11 +44,7 @@ impl AlgorithmDetector {
4444 self . extract_algorithms_from_finding_with_registry ( finding, registry) ?
4545 {
4646 for asset in algorithm_assets {
47- let key = format ! (
48- "{}:{}" ,
49- asset. name. as_ref( ) . unwrap_or( & "unknown" . to_string( ) ) ,
50- asset. bom_ref
51- ) ;
47+ let key = self . create_deduplication_key ( & asset) ;
5248 if seen_algorithms. insert ( key) {
5349 algorithms. push ( asset) ;
5450 }
@@ -60,11 +56,7 @@ impl AlgorithmDetector {
6056 let additional_algorithms =
6157 self . perform_deep_static_analysis_with_registry ( scan_path, registry) ?;
6258 for asset in additional_algorithms {
63- let key = format ! (
64- "{}:{}" ,
65- asset. name. as_ref( ) . unwrap_or( & "unknown" . to_string( ) ) ,
66- asset. bom_ref
67- ) ;
59+ let key = self . create_deduplication_key ( & asset) ;
6860 if seen_algorithms. insert ( key) {
6961 algorithms. push ( asset) ;
7062 }
@@ -76,11 +68,7 @@ impl AlgorithmDetector {
7668 self . extract_algorithms_from_finding_fallback ( finding) ?
7769 {
7870 for asset in algorithm_assets {
79- let key = format ! (
80- "{}:{}" ,
81- asset. name. as_ref( ) . unwrap_or( & "unknown" . to_string( ) ) ,
82- asset. bom_ref
83- ) ;
71+ let key = self . create_deduplication_key ( & asset) ;
8472 if seen_algorithms. insert ( key) {
8573 algorithms. push ( asset) ;
8674 }
@@ -89,7 +77,9 @@ impl AlgorithmDetector {
8977 }
9078 }
9179
92- Ok ( algorithms)
80+ // Merge duplicate algorithms with different parameter specificity
81+ let merged_algorithms = self . merge_algorithm_assets ( algorithms) ;
82+ Ok ( merged_algorithms)
9383 }
9484
9585 /// Extract algorithms from finding using pattern registry
@@ -326,6 +316,49 @@ impl AlgorithmDetector {
326316 Ok ( algorithms)
327317 }
328318
319+ /// Create a proper deduplication key based on algorithm properties, not bom_ref
320+ fn create_deduplication_key ( & self , asset : & CryptoAsset ) -> String {
321+ match & asset. asset_properties {
322+ AssetProperties :: Algorithm ( props) => {
323+ // For deduplication, use algorithm name and primitive only
324+ // This will merge different parameter variations of the same algorithm
325+ format ! ( "{}:{}" ,
326+ asset. name. as_ref( ) . unwrap_or( & "unknown" . to_string( ) ) ,
327+ props. primitive as u8
328+ )
329+ }
330+ _ => format ! ( "{}:{}" ,
331+ asset. name. as_ref( ) . unwrap_or( & "unknown" . to_string( ) ) ,
332+ asset. bom_ref
333+ )
334+ }
335+ }
336+
337+ /// Merge algorithm assets with the same name/primitive but different parameters
338+ fn merge_algorithm_assets ( & self , assets : Vec < CryptoAsset > ) -> Vec < CryptoAsset > {
339+ let mut merged_map: HashMap < String , CryptoAsset > = HashMap :: new ( ) ;
340+
341+ for asset in assets {
342+ let key = self . create_deduplication_key ( & asset) ;
343+
344+ if let Some ( existing) = merged_map. get_mut ( & key) {
345+ // Merge parameters if the new asset has more specific information
346+ if let ( AssetProperties :: Algorithm ( existing_props) , AssetProperties :: Algorithm ( new_props) ) =
347+ ( & mut existing. asset_properties , & asset. asset_properties ) {
348+
349+ // If existing has no parameters but new one does, use the new parameters
350+ if existing_props. parameter_set . is_none ( ) && new_props. parameter_set . is_some ( ) {
351+ existing_props. parameter_set = new_props. parameter_set . clone ( ) ;
352+ }
353+ }
354+ } else {
355+ merged_map. insert ( key, asset) ;
356+ }
357+ }
358+
359+ merged_map. into_values ( ) . collect ( )
360+ }
361+
329362 // Essential helper methods for fallback scenarios
330363
331364 fn create_rsa_algorithm ( & self , key_size : u32 ) -> CryptoAsset {
0 commit comments