Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[aes,rtl] Switch to Bivium-based masking PRNG implementation #20852

Merged
merged 2 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hw/ip/aes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ The AES unit supports the following features:
- Support for AES-192 can be removed to save area, and is enabled/disabled using a compile-time Verilog parameter
- First-order masking of the cipher core using domain-oriented masking (DOM) to deter side-channel analysis (SCA), can optionally be disabled using compile-time Verilog parameters (for more details see [Security Hardening](./doc/theory_of_operation.md#side-channel-analysis))
- Latency per 16 byte data block of 12/14/16 clock cycles (unmasked implementation) and 56/66/72 clock cycles (DOM) in AES-128/192/256 mode
- Automatic as well as software-initiated reseeding of internal pseudo-random number generators (PRNGs) with configurable reseeding rate resulting in max entropy consumption rates ranging from 286 Mbit/s to 0.035 Mbit/s (at 100 MHz).
- Automatic as well as software-initiated reseeding of internal pseudo-random number generators (PRNGs) with configurable reseeding rate resulting in max entropy consumption rates ranging from 343 Mbit/s to 0.042 Mbit/s (at 100 MHz).
- Countermeasures for deterring fault injection (FI) on the control path (for more details see [Security Hardening](./doc/theory_of_operation.md#fault-injection))
- Register-based data and control interface
- System key-manager interface for optional key sideload to not expose key material to the processor and other hosts attached to the system bus interconnect.
Expand Down
1 change: 1 addition & 0 deletions hw/ip/aes/aes.core
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ filesets:
- lowrisc:prim:lc_sync
- lowrisc:prim:lfsr
- lowrisc:prim:sparse_fsm
- lowrisc:prim:trivium
- lowrisc:prim:util
- lowrisc:ip:tlul
- lowrisc:ip:lc_ctrl_pkg
Expand Down
8 changes: 4 additions & 4 deletions hw/ip/aes/data/aes.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
desc: '''
Default seed of the PRNG used for masking.
'''
randcount: "160",
randcount: "288",
randtype: "data"
},
{ name: "RndCnstMaskingLfsrPerm",
Expand Down Expand Up @@ -731,21 +731,21 @@
desc: '''
3'b001: Reseed the masking PRNG once per block.
Invalid input values, i.e., values with multiple bits set and value 3'b000 are mapped to PER_1 (3'b001).
This results in a max entropy consumption rate of ~286 Mbit/s.
This results in a max entropy consumption rate of ~343 Mbit/s.
'''
},
{ value: "2",
name: "PER_64",
desc: '''
3'b010: Reseed the masking PRNG approximately once per every 64 blocks.
This results in a max entropy consumption rate of ~4.5 Mbit/s.
This results in a max entropy consumption rate of ~5.4 Mbit/s.
'''
},
{ value: "4",
name: "PER_8K",
desc: '''
3'b100: Reseed the masking PRNG approximately once per every 8192 blocks.
This results in an max entropy consumption rate of ~0.035 Mbit/s.
This results in a max entropy consumption rate of ~0.042 Mbit/s.
'''
}
]
Expand Down
6 changes: 3 additions & 3 deletions hw/ip/aes/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,9 @@ Invalid input values, i.e., values with multiple bits set and value 3'b000 are m

| Value | Name | Description |
|:--------|:-------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 0x1 | PER_1 | 3'b001: Reseed the masking PRNG once per block. Invalid input values, i.e., values with multiple bits set and value 3'b000 are mapped to PER_1 (3'b001). This results in a max entropy consumption rate of ~286 Mbit/s. |
| 0x2 | PER_64 | 3'b010: Reseed the masking PRNG approximately once per every 64 blocks. This results in a max entropy consumption rate of ~4.5 Mbit/s. |
| 0x4 | PER_8K | 3'b100: Reseed the masking PRNG approximately once per every 8192 blocks. This results in an max entropy consumption rate of ~0.035 Mbit/s. |
| 0x1 | PER_1 | 3'b001: Reseed the masking PRNG once per block. Invalid input values, i.e., values with multiple bits set and value 3'b000 are mapped to PER_1 (3'b001). This results in a max entropy consumption rate of ~343 Mbit/s. |
| 0x2 | PER_64 | 3'b010: Reseed the masking PRNG approximately once per every 64 blocks. This results in a max entropy consumption rate of ~5.4 Mbit/s. |
| 0x4 | PER_8K | 3'b100: Reseed the masking PRNG approximately once per every 8192 blocks. This results in a max entropy consumption rate of ~0.042 Mbit/s. |

Other values are reserved.

Expand Down
2 changes: 1 addition & 1 deletion hw/ip/aes/doc/theory_of_operation.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ If the AES unit is busy and running in CBC or CTR mode, the AES unit itself upda

The cipher core architecture of the AES unit is derived from the architecture proposed by Satoh et al.: ["A compact Rijndael Hardware Architecture with S-Box Optimization"](https://link.springer.com/chapter/10.1007%2F3-540-45682-1_15).
The expected circuit area in a 110nm CMOS technology is in the order of 12 - 22 kGE (unmasked implementation, AES-128 only).
The expected circuit area of the entire AES unit with masking enabled is around 110 kGE.
The expected circuit area of the entire AES unit with masking enabled is around 112 kGE.

For a description of the various sub modules, see the following sections.

Expand Down
16 changes: 3 additions & 13 deletions hw/ip/aes/dv/sva/aes_bind.sv
Original file line number Diff line number Diff line change
Expand Up @@ -52,28 +52,18 @@ if (`EN_MASKING) begin : gen_prng_bind
.rst_ni,

.entropy_masking_req(entropy_masking_req),
.entropy_masking_ack(entropy_masking_ack),

.entropy_i(edn_data),
.lfsr_q_0 (u_aes_core.u_aes_cipher_core.gen_masks.u_aes_prng_masking.gen_lfsrs[0].u_lfsr_chunk.
lfsr_q),
.lfsr_q_1 (u_aes_core.u_aes_cipher_core.gen_masks.u_aes_prng_masking.gen_lfsrs[1].u_lfsr_chunk.
lfsr_q),
.lfsr_q_2 (u_aes_core.u_aes_cipher_core.gen_masks.u_aes_prng_masking.gen_lfsrs[2].u_lfsr_chunk.
lfsr_q),
.lfsr_q_3 (u_aes_core.u_aes_cipher_core.gen_masks.u_aes_prng_masking.gen_lfsrs[3].u_lfsr_chunk.
lfsr_q),
.lfsr_q_4 (u_aes_core.u_aes_cipher_core.gen_masks.u_aes_prng_masking.gen_lfsrs[4].u_lfsr_chunk.
lfsr_q),
.state_q (u_aes_core.u_aes_cipher_core.gen_masks.u_aes_prng_masking.u_prim_bivium.state_q),

.reseed_rate (u_aes_core.prng_reseed_rate_q),
.block_ctr_expr (u_aes_core.u_aes_control.gen_fsm[0].gen_fsm_p.u_aes_control_fsm_i.
u_aes_control_fsm.block_ctr_expr),
.ctrl_state (u_aes_core.u_aes_control.gen_fsm[0].gen_fsm_p.u_aes_control_fsm_i.
u_aes_control_fsm.aes_ctrl_cs),
.ctrl_state_next(u_aes_core.u_aes_control.gen_fsm[0].gen_fsm_p.u_aes_control_fsm_i.
u_aes_control_fsm.aes_ctrl_ns),
.alert_fatal (u_aes_core.alert_fatal_o),
.seed_en (u_aes_core.u_aes_cipher_core.gen_masks.u_aes_prng_masking.prng_seed_en)
.alert_fatal (u_aes_core.alert_fatal_o)
);
end
endmodule
51 changes: 28 additions & 23 deletions hw/ip/aes/dv/sva/aes_masking_reseed_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,45 @@ interface aes_masking_reseed_if
import aes_pkg::*;
import aes_reg_pkg::*;
#(
parameter int unsigned EntropyWidth = edn_pkg::ENDPOINT_BUS_WIDTH,
parameter int unsigned Width = WidthPRDMasking, // Must be divisble by ChunkSize and 8
parameter int unsigned ChunkSize = ChunkSizePRDMasking, // Width of the LFSR primitives
localparam int unsigned NumChunks = Width/ChunkSize // derived parameter
parameter int unsigned EntropyWidth = edn_pkg::ENDPOINT_BUS_WIDTH,
parameter int unsigned StateWidth = prim_trivium_pkg::BiviumStateWidth
) (
input logic clk_i,
input logic rst_ni,

// Entropy request signal
// Entropy request/ack signals
input logic entropy_masking_req,
input logic entropy_masking_ack,

// Entropy input and LFSR state signals
// Entropy input and PRNG state signals
input logic [EntropyWidth-1:0] entropy_i,
input logic [ChunkSize-1:0] lfsr_q_0,
input logic [ChunkSize-1:0] lfsr_q_1,
input logic [ChunkSize-1:0] lfsr_q_2,
input logic [ChunkSize-1:0] lfsr_q_3,
input logic [ChunkSize-1:0] lfsr_q_4,
input logic [StateWidth-1:0] state_q,

// Control signals
input prs_rate_e reseed_rate,
input logic block_ctr_expr,
input aes_ctrl_e ctrl_state,
input aes_ctrl_e ctrl_state_next,
input logic alert_fatal,
input logic [NumChunks-1:0] seed_en
input logic block_ctr_expr,
input aes_ctrl_e ctrl_state,
input aes_ctrl_e ctrl_state_next,
input logic alert_fatal
);

// Make sure the LFSRs of the masking PRNG are set to the correct values obtained from EDN.
`ASSERT(MaskingPrngState0MatchesEdnInput_A, seed_en[0] |-> ##1 entropy_i == lfsr_q_0)
`ASSERT(MaskingPrngState1MatchesEdnInput_A, seed_en[1] |-> ##1 entropy_i == lfsr_q_1)
`ASSERT(MaskingPrngState2MatchesEdnInput_A, seed_en[2] |-> ##1 entropy_i == lfsr_q_2)
`ASSERT(MaskingPrngState3MatchesEdnInput_A, seed_en[3] |-> ##1 entropy_i == lfsr_q_3)
`ASSERT(MaskingPrngState4MatchesEdnInput_A, seed_en[4] |-> ##1 entropy_i == lfsr_q_4)
localparam int unsigned LastStatePartFractional = StateWidth % EntropyWidth != 0 ? 1 : 0;
localparam int unsigned NumStateParts = StateWidth / EntropyWidth + LastStatePartFractional;
localparam int unsigned NumBitsLastPart = StateWidth - (NumStateParts - 1) * EntropyWidth;
localparam int unsigned LastStatePart = NumStateParts - 1;

logic [NumStateParts-1:0] state_part_matches_input;
always_comb begin
state_part_matches_input = '0;
for (int unsigned i = 0; i < LastStatePart; i++) begin
state_part_matches_input[i] = state_q[i * EntropyWidth +: EntropyWidth] == entropy_i;
end
state_part_matches_input[LastStatePart] =
state_q[StateWidth - 1 -: NumBitsLastPart] == entropy_i[NumBitsLastPart-1:0];
end

// Make sure the entropy input obtained from EDN actually ends up in one part of the PRNG state.
`ASSERT(MaskingPrngStatePartMatchesEdnInput_A, entropy_masking_req && entropy_masking_ack
|-> ##1 |state_part_matches_input)

// Make sure the masking PRNG is reseeded when a new block is started while the block counter
// has expired unless a fatal alert is triggered.
Expand Down
Loading
Loading