@@ -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,12 @@ function validateMaxBufferLength(data, name) {
537551
538552let webidl ;
539553
554+ const kNormalizeAlgorithmOpts = {
555+ __proto__ : null ,
556+ prefix : 'Failed to normalize algorithm' ,
557+ context : 'passed algorithm' ,
558+ } ;
559+
540560// https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm
541561// adapted for Node.js from Deno's implementation
542562// https://github.com/denoland/deno/blob/v1.29.1/ext/crypto/00_crypto.js#L195
@@ -549,69 +569,56 @@ function normalizeAlgorithm(algorithm, op) {
549569 // 1.
550570 const registeredAlgorithms = kSupportedAlgorithms [ op ] ;
551571 // 2. 3.
552- const initialAlg = webidl . converters . Algorithm ( algorithm , {
553- prefix : 'Failed to normalize algorithm' ,
554- context : 'passed algorithm' ,
555- } ) ;
572+ const initialAlg = webidl . converters . Algorithm ( algorithm ,
573+ kNormalizeAlgorithmOpts ) ;
556574 // 4.
557575 let algName = initialAlg . name ;
558576
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 )
577+ // 5. Case-insensitive lookup via pre-built Map (O(1) instead of O(n)).
578+ const canonicalName = kAlgorithmNameMap [ op ] ?. get (
579+ StringPrototypeToUpperCase ( algName ) ) ;
580+ if ( canonicalName === undefined )
573581 throw lazyDOMException ( 'Unrecognized algorithm name' , 'NotSupportedError' ) ;
574582
583+ algName = canonicalName ;
584+ const desiredType = registeredAlgorithms [ algName ] ;
585+
575586 // Fast path everything below if the registered dictionary is null
576587 if ( desiredType === null )
577588 return { name : algName } ;
578589
579590 // 6.
580591 const normalizedAlgorithm = webidl . converters [ desiredType ] (
581592 { __proto__ : algorithm , name : algName } ,
582- {
583- prefix : 'Failed to normalize algorithm' ,
584- context : 'passed algorithm' ,
585- } ,
593+ kNormalizeAlgorithmOpts ,
586594 ) ;
587595 // 7.
588596 normalizedAlgorithm . name = algName ;
589597
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' ) ;
598+ // 9. 10. Pre-computed keys and types from simpleAlgorithmDictionaries.
599+ const dictMeta = simpleAlgorithmDictionaries [ desiredType ] ;
600+ if ( dictMeta ) {
601+ const { keys : dictKeys , types : dictTypes } = dictMeta ;
602+ for ( let i = 0 ; i < dictKeys . length ; i ++ ) {
603+ const member = dictKeys [ i ] ;
604+ const idlType = dictTypes [ member ] ;
605+ const idlValue = normalizedAlgorithm [ member ] ;
606+ // 3.
607+ if ( idlType === 'BufferSource' && idlValue ) {
608+ const isView = ArrayBufferIsView ( idlValue ) ;
609+ normalizedAlgorithm [ member ] = TypedArrayPrototypeSlice (
610+ new Uint8Array (
611+ isView ? getDataViewOrTypedArrayBuffer ( idlValue ) : idlValue ,
612+ isView ? getDataViewOrTypedArrayByteOffset ( idlValue ) : 0 ,
613+ isView ? getDataViewOrTypedArrayByteLength ( idlValue ) : ArrayBufferPrototypeGetByteLength ( idlValue ) ,
614+ ) ,
615+ ) ;
616+ } else if ( idlType === 'HashAlgorithmIdentifier' ) {
617+ normalizedAlgorithm [ member ] = normalizeAlgorithm ( idlValue , 'digest' ) ;
618+ } else if ( idlType === 'AlgorithmIdentifier' ) {
619+ // This extension point is not used by any supported algorithm (yet?)
620+ throw lazyDOMException ( 'Not implemented.' , 'NotSupportedError' ) ;
621+ }
615622 }
616623 }
617624
0 commit comments