@@ -16,6 +16,7 @@ const {
1616 ObjectKeys,
1717 ObjectPrototypeHasOwnProperty,
1818 PromiseWithResolvers,
19+ SafeMap,
1920 StringPrototypeToUpperCase,
2021 Symbol,
2122 TypedArrayPrototypeGetBuffer,
@@ -453,8 +454,11 @@ const experimentalAlgorithms = [
453454] ;
454455
455456// Transform the algorithm definitions into the operation-keyed structure
457+ // Also builds a parallel Map<UPPERCASED_NAME, canonicalName> per operation
458+ // for O(1) case-insensitive algorithm name lookup in normalizeAlgorithm.
456459function createSupportedAlgorithms ( algorithmDefs ) {
457460 const result = { } ;
461+ const nameMap = { } ;
458462
459463 for ( const { 0 : algorithmName , 1 : operations } of ObjectEntries ( algorithmDefs ) ) {
460464 // Skip algorithms that are conditionally not supported
@@ -465,6 +469,8 @@ function createSupportedAlgorithms(algorithmDefs) {
465469
466470 for ( const { 0 : operation , 1 : dict } of ObjectEntries ( operations ) ) {
467471 result [ operation ] ||= { } ;
472+ nameMap [ operation ] ||= new SafeMap ( ) ;
473+ nameMap [ operation ] . set ( StringPrototypeToUpperCase ( algorithmName ) , algorithmName ) ;
468474
469475 // Add experimental warnings for experimental algorithms
470476 if ( ArrayPrototypeIncludes ( experimentalAlgorithms , algorithmName ) ) {
@@ -482,12 +488,14 @@ function createSupportedAlgorithms(algorithmDefs) {
482488 }
483489 }
484490
485- return result ;
491+ return { algorithms : result , nameMap } ;
486492}
487493
488- const kSupportedAlgorithms = createSupportedAlgorithms ( kAlgorithmDefinitions ) ;
494+ const { algorithms : kSupportedAlgorithms , nameMap : kAlgorithmNameMap } =
495+ createSupportedAlgorithms ( kAlgorithmDefinitions ) ;
489496
490497const simpleAlgorithmDictionaries = {
498+ __proto__ : null ,
491499 AesCbcParams : { iv : 'BufferSource' } ,
492500 AesCtrParams : { counter : 'BufferSource' } ,
493501 AeadParams : { iv : 'BufferSource' , additionalData : 'BufferSource' } ,
@@ -527,6 +535,12 @@ const simpleAlgorithmDictionaries = {
527535 TurboShakeParams : { } ,
528536} ;
529537
538+ // Pre-compute ObjectKeys() for each dictionary entry at module init
539+ // to avoid allocating a new keys array on every normalizeAlgorithm call.
540+ for ( const { 0 : name , 1 : types } of ObjectEntries ( simpleAlgorithmDictionaries ) ) {
541+ simpleAlgorithmDictionaries [ name ] = { keys : ObjectKeys ( types ) , types } ;
542+ }
543+
530544function validateMaxBufferLength ( data , name ) {
531545 if ( data . byteLength > kMaxBufferLength ) {
532546 throw lazyDOMException (
@@ -537,6 +551,11 @@ function validateMaxBufferLength(data, name) {
537551
538552let webidl ;
539553
554+ const kNormalizeAlgorithmOpts = {
555+ prefix : 'Failed to normalize algorithm' ,
556+ context : 'passed algorithm' ,
557+ } ;
558+
540559// https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm
541560// adapted for Node.js from Deno's implementation
542561// https://github.com/denoland/deno/blob/v1.29.1/ext/crypto/00_crypto.js#L195
@@ -549,69 +568,56 @@ function normalizeAlgorithm(algorithm, op) {
549568 // 1.
550569 const registeredAlgorithms = kSupportedAlgorithms [ op ] ;
551570 // 2. 3.
552- const initialAlg = webidl . converters . Algorithm ( algorithm , {
553- prefix : 'Failed to normalize algorithm' ,
554- context : 'passed algorithm' ,
555- } ) ;
571+ const initialAlg = webidl . converters . Algorithm ( algorithm ,
572+ kNormalizeAlgorithmOpts ) ;
556573 // 4.
557574 let algName = initialAlg . name ;
558575
559- // 5.
560- let desiredType ;
561- for ( const key in registeredAlgorithms ) {
562- if ( ! ObjectPrototypeHasOwnProperty ( registeredAlgorithms , key ) ) {
563- continue ;
564- }
565- if (
566- StringPrototypeToUpperCase ( key ) === StringPrototypeToUpperCase ( algName )
567- ) {
568- algName = key ;
569- desiredType = registeredAlgorithms [ key ] ;
570- }
571- }
572- if ( desiredType === undefined )
576+ // 5. Case-insensitive lookup via pre-built Map (O(1) instead of O(n)).
577+ const canonicalName = kAlgorithmNameMap [ op ] ?. get (
578+ StringPrototypeToUpperCase ( algName ) ) ;
579+ if ( canonicalName === undefined )
573580 throw lazyDOMException ( 'Unrecognized algorithm name' , 'NotSupportedError' ) ;
574581
582+ algName = canonicalName ;
583+ const desiredType = registeredAlgorithms [ algName ] ;
584+
575585 // Fast path everything below if the registered dictionary is null
576586 if ( desiredType === null )
577587 return { name : algName } ;
578588
579589 // 6.
580590 const normalizedAlgorithm = webidl . converters [ desiredType ] (
581591 { __proto__ : algorithm , name : algName } ,
582- {
583- prefix : 'Failed to normalize algorithm' ,
584- context : 'passed algorithm' ,
585- } ,
592+ kNormalizeAlgorithmOpts ,
586593 ) ;
587594 // 7.
588595 normalizedAlgorithm . name = algName ;
589596
590- // 9.
591- const dict = simpleAlgorithmDictionaries [ desiredType ] ;
592- // 10.
593- const dictKeys = dict ? ObjectKeys ( dict ) : [ ] ;
594- for ( let i = 0 ; i < dictKeys . length ; i ++ ) {
595- const member = dictKeys [ i ] ;
596- if ( ! ObjectPrototypeHasOwnProperty ( dict , member ) )
597- continue ;
598- const idlType = dict [ member ] ;
599- const idlValue = normalizedAlgorithm [ member ] ;
600- // 3.
601- if ( idlType === 'BufferSource' && idlValue ) {
602- const isView = ArrayBufferIsView ( idlValue ) ;
603- normalizedAlgorithm [ member ] = TypedArrayPrototypeSlice (
604- new Uint8Array (
605- isView ? getDataViewOrTypedArrayBuffer ( idlValue ) : idlValue ,
606- isView ? getDataViewOrTypedArrayByteOffset ( idlValue ) : 0 ,
607- isView ? getDataViewOrTypedArrayByteLength ( idlValue ) : ArrayBufferPrototypeGetByteLength ( idlValue ) ,
608- ) ,
609- ) ;
610- } else if ( idlType === 'HashAlgorithmIdentifier' ) {
611- normalizedAlgorithm [ member ] = normalizeAlgorithm ( idlValue , 'digest' ) ;
612- } else if ( idlType === 'AlgorithmIdentifier' ) {
613- // This extension point is not used by any supported algorithm (yet?)
614- throw lazyDOMException ( 'Not implemented.' , 'NotSupportedError' ) ;
597+ // 9. 10. Pre-computed keys and types from simpleAlgorithmDictionaries.
598+ const dictMeta = simpleAlgorithmDictionaries [ desiredType ] ;
599+ if ( dictMeta ) {
600+ const { keys : dictKeys , types : dictTypes } = dictMeta ;
601+ for ( let i = 0 ; i < dictKeys . length ; i ++ ) {
602+ const member = dictKeys [ i ] ;
603+ const idlType = dictTypes [ member ] ;
604+ const idlValue = normalizedAlgorithm [ member ] ;
605+ // 3.
606+ if ( idlType === 'BufferSource' && idlValue ) {
607+ const isView = ArrayBufferIsView ( idlValue ) ;
608+ normalizedAlgorithm [ member ] = TypedArrayPrototypeSlice (
609+ new Uint8Array (
610+ isView ? getDataViewOrTypedArrayBuffer ( idlValue ) : idlValue ,
611+ isView ? getDataViewOrTypedArrayByteOffset ( idlValue ) : 0 ,
612+ isView ? getDataViewOrTypedArrayByteLength ( idlValue ) : ArrayBufferPrototypeGetByteLength ( idlValue ) ,
613+ ) ,
614+ ) ;
615+ } else if ( idlType === 'HashAlgorithmIdentifier' ) {
616+ normalizedAlgorithm [ member ] = normalizeAlgorithm ( idlValue , 'digest' ) ;
617+ } else if ( idlType === 'AlgorithmIdentifier' ) {
618+ // This extension point is not used by any supported algorithm (yet?)
619+ throw lazyDOMException ( 'Not implemented.' , 'NotSupportedError' ) ;
620+ }
615621 }
616622 }
617623
0 commit comments