Skip to content

Commit

Permalink
[aes,dv] Test AES-GCM save and restore feature
Browse files Browse the repository at this point in the history
This commit adds a directed test that checks whether AES-GCM
operations can be stored and restored using the dedicated feature.

Signed-off-by: Pascal Nasahl <[email protected]>
  • Loading branch information
nasahlpa committed Feb 19, 2025
1 parent 6416650 commit 3da9541
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 12 deletions.
7 changes: 7 additions & 0 deletions hw/ip/aes/data/aes_testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@
stage: V2
tests: ["aes_nist_vectors_gcm"]
}
{
name: gcm_save_restore
desc: '''
Test whether an AES-GCM operation can be saved and restored.'''
stage: V2
tests: ["aes_gcm_save_restore"]
}
{
name: reset_recovery
desc: '''
Expand Down
5 changes: 5 additions & 0 deletions hw/ip/aes/dv/aes_base_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@
uvm_test: aes_fi_test
uvm_test_seq: aes_readability_vseq
}
{
name: aes_gcm_save_restore
uvm_test: aes_gcm_save_restore_test
uvm_test_seq: aes_gcm_save_restore_vseq
}
// Regular tests for which the scoreboard is active.
{
name: aes_smoke
Expand Down
1 change: 1 addition & 0 deletions hw/ip/aes/dv/env/aes_env.core
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ filesets:
- seq_lib/aes_core_fi_vseq.sv: {is_include_file: true}
- seq_lib/aes_readability_vseq.sv: {is_include_file: true}
- seq_lib/aes_stress_all_vseq.sv: {is_include_file: true}
- seq_lib/aes_gcm_save_restore_vseq.sv: {is_include_file: true}
file_type: systemVerilogSource

generate:
Expand Down
12 changes: 7 additions & 5 deletions hw/ip/aes/dv/env/aes_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ package aes_env_pkg;
parameter uint NUM_EDN = 1;

typedef enum int {
AES_CFG = 0,
AES_DATA = 1,
AES_ERR_INJ = 2,
AES_GCM_AAD = 3,
AES_GCM_TAG = 4
AES_CFG = 0,
AES_DATA = 1,
AES_ERR_INJ = 2,
AES_GCM_AAD = 3,
AES_GCM_TAG = 4,
AES_GCM_SAVE = 5,
AES_GCM_RESTORE = 6
} aes_item_type_e;

typedef enum int {
Expand Down
2 changes: 1 addition & 1 deletion hw/ip/aes/dv/env/aes_message_item.sv
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ class aes_message_item extends uvm_sequence_item;
if (item.mode == AES_GCM) begin
if (item.item_type == AES_GCM_AAD) begin
add_aad_item(item);
end else begin
end else if (item.item_type == AES_DATA) begin
`uvm_info(`gfn, $sformatf("ADDING DATA ITEM TYPE IS %s", item.item_type.name()), UVM_LOW)
add_data_item(item);
end
Expand Down
10 changes: 6 additions & 4 deletions hw/ip/aes/dv/env/aes_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ class aes_scoreboard extends cip_base_scoreboard #(

function void on_ctrl_gcm_shadowed_write(logic [31:0] wdata);
case (get_field_val(ral.ctrl_gcm_shadowed.phase, wdata))
GCM_INIT: input_item.item_type = AES_CFG;
GCM_TEXT: input_item.item_type = AES_DATA;
GCM_AAD: input_item.item_type = AES_GCM_AAD;
GCM_TAG: input_item.item_type = AES_GCM_TAG;
GCM_INIT: input_item.item_type = AES_CFG;
GCM_TEXT: input_item.item_type = AES_DATA;
GCM_AAD: input_item.item_type = AES_GCM_AAD;
GCM_TAG: input_item.item_type = AES_GCM_TAG;
GCM_SAVE: input_item.item_type = AES_GCM_SAVE;
GCM_RESTORE: input_item.item_type = AES_GCM_RESTORE;
default: input_item.item_type = AES_CFG;
endcase

Expand Down
4 changes: 2 additions & 2 deletions hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,12 @@ class aes_base_vseq extends cip_base_vseq #(
// Write the shadwoed CTRL register.
status_t status;
// Setup fields one by one (0) or all fields together (1).
bit setup_mode = 0;
bit setup_mode = 1;
// Trigger a control update error (1) or not (0). Only applicable if setup_mode = 1.
bit control_update_error = 0;
// Index of the field which shall trigger the control update error.
int idx_error_field = 0;
`DV_CHECK_STD_RANDOMIZE_FATAL(setup_mode)
//`DV_CHECK_STD_RANDOMIZE_FATAL(setup_mode)
if ($urandom_range(1, 100) > 95) control_update_error = 1;
idx_error_field = $urandom_range(0, 5);
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
Expand Down
206 changes: 206 additions & 0 deletions hw/ip/aes/dv/env/seq_lib/aes_gcm_save_restore_vseq.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// Test processes several AES-GCM messages. During each message, at a random
// item, the GCM save and restore feature is tested. Here, before the new item
// is processed, the current state is saved, the registers are cleared, and the
// state is restored. Then, the test continues processing the item.

// scoreboard is disabled for this test
class aes_gcm_save_restore_vseq extends aes_base_vseq;
`uvm_object_utils(aes_gcm_save_restore_vseq)

`uvm_object_new
aes_message_item msg;
bit rst_set;
bit do_b2b = 0;

task body();
`uvm_info(`gfn, $sformatf("\n\n\t ----| STARTING AES-GCM SAVE & RESTORE SEQUENCE |----\n %s",
cfg.convert2string()), UVM_MEDIUM)

fork
// Start sideload (even if not used).
start_sideload_seq();
join_none

// Generate list of messages.
generate_message_queue();

// Process all messages.
while (message_queue.size() > 0 ) begin
bit new_aad = 1;
bit new_data = 1;
int item_cnt = 1;
int save_restore_item;
int crypto_res;
int aad_len, data_len;
bit operation;
bit [3:0][31:0] predicted_tag;
bit [3:0][31:0] saved_gcm_state, saved_iv;
aes_seq_item cfg_item = new();
aes_seq_item cfg_item_restored_iv = new();
aes_seq_item data_item = new();

`uvm_info(`gfn, $sformatf("Starting New Message - messages left %d",
message_queue.size() ), UVM_MEDIUM)

msg = message_queue.pop_back();
aad_len = msg.aad_length;
data_len = msg.message_length;
generate_aes_item_queue(msg);

cfg_item = aes_item_queue.pop_back();
msg.add_start_msg_item(cfg_item);

// Wait until the DUT is idle. This is required to start the configuration.
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
// Configure the DUT. Depending on the configuration, this might trigger a PRNG reseed
// operation.
csr_spinwait(.ptr(ral.status.idle) , .exp_data(1'b1));
setup_dut(cfg_item);

// Wait until the DUT is idle. This is required to provide key and IV.
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
// Provide key, IV and data.
write_data_key_iv(cfg_item, cfg_item, 1, cfg_item.manual_op, 0, 0, rst_set);
if (cfg_item.manual_op && !rst_set) trigger();
if (cfg_item.manual_op && !rst_set) trigger();

// At which item do we perform the save and restore?
// Do not perform before we have processed the first item and also when
// handling the tag.
save_restore_item = 0;//$urandom_range(2, aes_item_queue.size() - 1);

// Process all items.
while (aes_item_queue.size() > 0 ) begin
int valid_bytes;
// Wait until the DUT is idle.
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));

data_item = aes_item_queue.pop_back();
`uvm_info(`gfn, $sformatf("\n\t ----AES ITEM %s",
data_item.convert2string()), UVM_MEDIUM)

if (item_cnt == save_restore_item) begin
`uvm_info(`gfn, $sformatf("Saving AES-GCM state before processing item %d",
item_cnt), UVM_MEDIUM)
set_gcm_phase(GCM_SAVE, 16, 0);
if (cfg_item.manual_op) trigger();
// Save the current AES-GCM context.
csr_spinwait(.ptr(ral.status.output_valid), .exp_data(1'b1));
read_data(saved_gcm_state, do_b2b);
// Save the current IV.
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
read_iv(saved_iv, do_b2b);
`downcast(cfg_item_restored_iv, cfg_item.clone());
cfg_item_restored_iv.iv = saved_iv;
cfg_item_restored_iv.iv[3] = '0; // Clear upper IV bits to restore the original IV.
// Clear the AES IV, data in, and data out registers.
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
clear_regs(2'b11);
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
`uvm_info(`gfn, $sformatf("Restoring AES-GCM state before processing item %d",
item_cnt), UVM_MEDIUM)
// Reconfigure the initial IV and the key.
write_data_key_iv(cfg_item_restored_iv, data_item, 1, cfg_item.manual_op,
0, 0, rst_set);
if (cfg_item.manual_op) trigger();
if (cfg_item.manual_op) trigger();

// Restore the saved AES-GCM context.
set_gcm_phase(GCM_RESTORE, 16, 1);
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
add_data(saved_gcm_state, do_b2b);
// Restore the saved IV.
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
write_iv(saved_iv, do_b2b);
if (cfg_item.manual_op) trigger();
`uvm_info(`gfn, $sformatf("Proceeding with item %d", item_cnt), UVM_MEDIUM)
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
// Enforce setting the GCM phase for the next item.
new_aad = 1;
new_data = 1;
end

if (data_item.item_type == AES_GCM_AAD) begin
if (new_aad || data_item.data_len[3:0] != 4'd0) begin
// Configure AAD phase as this is either the first AAD block or a
// partial block.
valid_bytes = data_item.data_len == 0 ? 16 : data_item.data_len;
set_gcm_phase(GCM_AAD, valid_bytes, 0);
new_aad = 0;
end
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
add_data(data_item.data_in, do_b2b);
if (cfg_item.manual_op) trigger();
// Add AAD to message.
msg.add_aad_item(data_item);
end else if (data_item.item_type == AES_DATA) begin
if (new_data || data_item.data_len[3:0] != 4'd0) begin
// Configure TEXT phase as this is either the first plaintext block or a
// partial block.
valid_bytes = data_item.data_len == 0 ? 16 : data_item.data_len;
set_gcm_phase(GCM_TEXT, valid_bytes, 0);
new_aad = 0;
end
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
add_data(data_item.data_in, do_b2b);
if (cfg_item.manual_op) trigger();
csr_spinwait(.ptr(ral.status.output_valid), .exp_data(1'b1));
read_data(data_item.data_out, do_b2b);
// Add input and output data block to message.
msg.add_data_item(data_item);
end else if (data_item.item_type == AES_GCM_TAG) begin
set_gcm_phase(GCM_TAG, 16, 0);
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
add_data(data_item.data_in, do_b2b);
if (cfg_item.manual_op) trigger();
csr_spinwait(.ptr(ral.status.output_valid), .exp_data(1'b1));
read_data(data_item.data_out, do_b2b);
// Add tag to message.
msg.add_tag_item(data_item);
end
item_cnt++;
end

// Check if we got the correct output.
operation = msg.aes_operation == AES_ENC ? 1'b0 :
msg.aes_operation == AES_DEC ? 1'b1 : 1'b0;
msg.alloc_predicted_msg();
c_dpi_aes_crypt_message(cfg.ref_model, operation, msg.aes_mode, msg.aes_iv,
msg.aes_keylen, msg.aes_key[0] ^ msg.aes_key[1],
data_len, aad_len, msg.input_msg,
msg.input_aad, msg.output_tag, msg.predicted_msg,
predicted_tag, crypto_res);

// Check the error code of the c_dpi library.
if (crypto_res < 0) begin
// The underlying c_dpi cyrpto lib returns an error code < 0 if something
// is wrong.
`uvm_fatal(`gfn, "c_dpi crypto lib error detected!\n")
end

// Check output data.
for (int n =0 ; n < data_len; n++) begin
if ((msg.output_msg[n] != msg.predicted_msg[n]) && ~msg.output_cleared[n]) begin
`uvm_fatal(`gfn, $sformatf(" output_msg[%d] (0x%x) != predicted_msg[%d] (0x%x) \n",
n, msg.output_msg[n], n, msg.predicted_msg[n]))
end
end

// Check tag.
if (msg.aes_operation == AES_ENC) begin
`uvm_info(`gfn, $sformatf("DOING TAG CHECK"), UVM_MEDIUM)
predicted_tag = aes_transpose(predicted_tag);
foreach(predicted_tag[n]) begin
if ((predicted_tag[n] != msg.output_tag[n]) && msg.output_tag_vld) begin
`uvm_fatal(`gfn, $sformatf(" predicted_tag[%d] (0x%x) != output_tag[%d] (0x%x) \n",
n, predicted_tag[n], n, msg.output_tag[n]))
end
end
end
end
endtask : body
endclass
1 change: 1 addition & 0 deletions hw/ip/aes/dv/env/seq_lib/aes_vseq_list.sv
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
`include "aes_core_fi_vseq.sv"
`include "aes_readability_vseq.sv"
`include "aes_stress_all_vseq.sv"
`include "aes_gcm_save_restore_vseq.sv"
56 changes: 56 additions & 0 deletions hw/ip/aes/dv/tests/aes_gcm_save_restore_test.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

class aes_gcm_save_restore_test extends aes_base_test;

`uvm_component_utils(aes_gcm_save_restore_test)
`uvm_component_new


virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
configure_env();
endfunction

function void configure_env();
super.configure_env();
// disable scoreboard for this directed test
cfg.en_scb = 0;
cfg.error_types = 0; // no errors
cfg.num_messages_min = 1;
cfg.num_messages_max = 5;
// message related knobs
cfg.ecb_weight = 0;
cfg.cbc_weight = 0;
cfg.ctr_weight = 0;
cfg.ofb_weight = 0;
cfg.cfb_weight = 0;
cfg.gcm_weight = 100;

cfg.message_len_min = 16; // one block (16bytes=128bits)
cfg.message_len_max = 123; //
cfg.aad_len_min = 16; //
cfg.aad_len_max = 123; //
cfg.manual_operation_pct = 50;
cfg.use_key_mask = 0;

cfg.fixed_data_en = 0;
cfg.fixed_key_en = 0;

cfg.fixed_operation_en = 0;
cfg.fixed_operation = aes_pkg::AES_DEC;

cfg.fixed_keylen_en = 0;
cfg.fixed_keylen = 3'b001;

cfg.fixed_iv_en = 0;
cfg.fixed_aad_en = 0;

cfg.random_data_key_iv_order = 0;
cfg.read_prob = 100;
cfg.write_prob = 100;

`DV_CHECK_RANDOMIZE_FATAL(cfg)
endfunction
endclass : aes_gcm_save_restore_test
1 change: 1 addition & 0 deletions hw/ip/aes/dv/tests/aes_test.core
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ filesets:
- aes_manual_config_err_test.sv: {is_include_file: true}
- aes_reseed_test.sv: {is_include_file: true}
- aes_fi_test.sv: {is_include_file: true}
- aes_gcm_save_restore_test.sv: {is_include_file: true}
file_type: systemVerilogSource

targets:
Expand Down
1 change: 1 addition & 0 deletions hw/ip/aes/dv/tests/aes_test_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ package aes_test_pkg;
`include "aes_manual_config_err_test.sv"
`include "aes_reseed_test.sv"
`include "aes_fi_test.sv"
`include "aes_gcm_save_restore_test.sv"
endpackage

0 comments on commit 3da9541

Please sign in to comment.