Estoy trabajando en un proyecto de cifrado / descifrado AES que puede manejar AES-128, AES-192 y AES-256. La longitud de la clave de cifrado se elige en el momento de la compilación. El módulo en el que estoy trabajando genera el programa clave . El algoritmo para hacerlo varía ligeramente para AES 256 frente a los otros dos, así que tengo dos funciones diferentes para manejarlos. Mi módulo de expansión clave tiene un solo bloque lógico combinacional:
always_comb
begin
expandedKey.expBlocks[0] = key;
for (int i=1; i<='NUM_KEY_EXP_ROUNDS; ++i)
expandedKey.expBlocks[i] = expandBlock(i, expandedKey.expBlocks[i-1]);
end
Estas son las funciones que el código anterior puede llamar:
'ifndef AES_256 // expanding a 128- or 192-bit key
function automatic expandBlock(input integer round, expKeyBlock_t prevBlock);
// ... function body
endfunction
'else // Expanding a 256-bit key
function automatic expandBlock(input integer round, expKeyBlock_t prevBlock);
// ... function body
endfunction
'endif // 'ifndef AES_256
El problema con esta configuración es que dificulta las pruebas. En mi banco de pruebas, quiero poder crear una instancia de este módulo en cada configuración AES_XXX y simular los tres sin volver a compilar para facilitar las pruebas de regresión.
He considerado usar parámetros en su lugar:
'ifndef AES_256 // expanding a 128- or 192-bit key
parameter logic SELECT_AES_256 = 1'b0;
'else // Expanding a 256-bit key
parameter logic SELECT_AES_256 = 1'b1;
'endif // 'ifndef AES_256
always_comb
begin
expandedKey.expBlocks[0] = key;
// I chose to put the SELECT_AES_256 check outside the loop so it isn't
// checked on every loop iteration, potentially generating even more extra
// hardware
if (SELECT_AES_256)
for (int i=1; i<='NUM_KEY_EXP_ROUNDS; ++i)
expandedKey.expBlocks[i] = expandBlock_long(i, expandedKey.expBlocks[i-1]);
else
for (int i=1; i<='NUM_KEY_EXP_ROUNDS; ++i)
expandedKey.expBlocks[i] = expandBlock_short(i, expandedKey.expBlocks[i-1]);
end
function automatic expandBlock_short(input integer expRound, expKeyBlock_t prevBlock);
// ... function body
endfunction
function automatic expandBlock_long(input integer expRound, expKeyBlock_t prevBlock);
// ... function body
endfunction
El uso de un parámetro me permitiría crear una instancia del módulo en cualquier configuración que desee, pero tiene un código duplicado y, finalmente, dependeré de las optimizaciones del sintetizador para eliminar el hardware no utilizado. No me gustan ninguno de esos atributos.
La pregunta
¿Hay alguna forma en que pueda refactorizar este código para poder elegir a qué función expandBlock
se llama cuando se crea una instancia del módulo, sin el código duplicado y el hardware potencialmente duplicado?