Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 1 | // Copyright lowRISC contributors. |
| 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | // SPDX-License-Identifier: Apache-2.0 |
| 4 | // |
| 5 | // Domain-Oriented Masking GF(2) Multiplier with 2-shares |
| 6 | // ref: Higher-Order Side-Channel Protected Implementations of Keccak |
| 7 | // https://eprint.iacr.org/2017/395.pdf |
| 8 | // |
| 9 | // q0 = a0 & b0 + (a0 & b1 + z) |
| 10 | // q1 = a1 & b1 + (a1 & b0 + z) |
| 11 | // () ==> registered |
| 12 | // |
| 13 | // all input should be stable for two clocks |
| 14 | // as the output is valid after a clock |
| 15 | // For z, it can use other slice from the state |
| 16 | // as it is fairly random w.r.t the current inputs. |
| 17 | |
| 18 | // General formula of Q in the paper |
| 19 | // Qi = t{i,i} + Sig(j>i,d)(t{i,j}+Z{i+j*(j-1)/2}) + Sig(j<i,d)(t{i,j}+Z{j+i*(i-1)/2}) |
| 20 | // for d=1 (NumShare 2 for first order protection) |
| 21 | // Q0 = t{0,0} + Sig(j>0,1)(t{0,j}+Z{j(j-1)/2}) + Sig(j<0,d)(..) |
| 22 | // = a0&b0 + (a0&b1 + z0 + 0) |
| 23 | // Q1 = t{1,1} + sig(j>1,1)(...) + sig(j<1,1)(t{1,j} + Z{j}) |
| 24 | // = a1&b1 + (0 + a1&b0 + z0) |
| 25 | |
| 26 | `include "prim_assert.sv" |
| 27 | |
| 28 | module prim_dom_and_2share #( |
Pirmin Vogel | cd40a66 | 2022-02-21 18:40:13 +0100 | [diff] [blame] | 29 | parameter int DW = 64, // Input width |
| 30 | parameter bit Pipeline = 1'b0 // Enable full pipelining |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 31 | ) ( |
| 32 | input clk_i, |
Eunchan Kim | 0210f99 | 2020-08-13 18:02:44 -0700 | [diff] [blame] | 33 | input rst_ni, |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 34 | |
| 35 | input [DW-1:0] a0_i, // share0 of a |
| 36 | input [DW-1:0] a1_i, // share1 of a |
| 37 | input [DW-1:0] b0_i, // share0 of b |
| 38 | input [DW-1:0] b1_i, // share1 of b |
Pirmin Vogel | 217328d | 2022-02-21 15:35:59 +0100 | [diff] [blame] | 39 | input z_valid_i, // random number input validity |
| 40 | input [DW-1:0] z_i, // random number |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 41 | |
| 42 | output logic [DW-1:0] q0_o, // share0 of q |
Pirmin Vogel | 773de67 | 2022-04-18 14:59:55 +0200 | [diff] [blame] | 43 | output logic [DW-1:0] q1_o, // share1 of q |
| 44 | output logic [DW-1:0] prd_o // pseudo-random data for other instances |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 45 | ); |
| 46 | |
| 47 | logic [DW-1:0] t0_d, t0_q, t1_d, t1_q; |
Pirmin Vogel | cd40a66 | 2022-02-21 18:40:13 +0100 | [diff] [blame] | 48 | logic [DW-1:0] t_a0b0, t_a1b1; |
| 49 | logic [DW-1:0] t_a0b0_d, t_a1b1_d; |
| 50 | logic [DW-1:0] t_a0b1, t_a1b0; |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 51 | |
Pirmin Vogel | e58f674 | 2022-02-21 15:41:50 +0100 | [diff] [blame] | 52 | ///////////////// |
| 53 | // Calculation // |
| 54 | ///////////////// |
| 55 | // Inner-domain terms |
Pirmin Vogel | cd40a66 | 2022-02-21 18:40:13 +0100 | [diff] [blame] | 56 | assign t_a0b0_d = a0_i & b0_i; |
| 57 | assign t_a1b1_d = a1_i & b1_i; |
Pirmin Vogel | e58f674 | 2022-02-21 15:41:50 +0100 | [diff] [blame] | 58 | |
| 59 | // Cross-domain terms |
| 60 | assign t_a0b1 = a0_i & b1_i; |
| 61 | assign t_a1b0 = a1_i & b0_i; |
| 62 | |
| 63 | /////////////// |
| 64 | // Resharing // |
| 65 | /////////////// |
| 66 | // Resharing of cross-domain terms |
| 67 | |
| 68 | // Preserve the logic sequence for XOR not to proceed cross-domain AND. |
| 69 | prim_xor2 #( |
| 70 | .Width ( DW*2 ) |
| 71 | ) u_prim_xor_t01 ( |
| 72 | .in0_i ( {t_a0b1, t_a1b0} ), |
| 73 | .in1_i ( {z_i, z_i} ), |
| 74 | .out_o ( {t0_d, t1_d} ) |
| 75 | ); |
| 76 | |
| 77 | // Register stage |
| 78 | prim_flop_en #( |
| 79 | .Width ( DW*2 ), |
| 80 | .ResetValue ( '0 ) |
| 81 | ) u_prim_flop_t01 ( |
| 82 | .clk_i ( clk_i ), |
| 83 | .rst_ni ( rst_ni ), |
| 84 | .en_i ( z_valid_i ), |
| 85 | .d_i ( {t0_d, t1_d} ), |
| 86 | .q_o ( {t0_q, t1_q} ) |
| 87 | ); |
| 88 | |
Pirmin Vogel | cd40a66 | 2022-02-21 18:40:13 +0100 | [diff] [blame] | 89 | ///////////////////////// |
| 90 | // Optional Pipelining // |
| 91 | ///////////////////////// |
| 92 | |
| 93 | if (Pipeline == 1'b1) begin : gen_inner_domain_regs |
| 94 | // Add pipeline registers on inner-domain terms prior to integration. This allows accepting new |
| 95 | // input data every clock cycle and prevents SCA leakage occurring due to the integration of |
| 96 | // reshared cross-domain terms with inner-domain terms derived from different input data. |
| 97 | |
| 98 | logic [DW-1:0] t_a0b0_q, t_a1b1_q; |
| 99 | prim_flop_en #( |
| 100 | .Width ( DW*2 ), |
| 101 | .ResetValue ( '0 ) |
| 102 | ) u_prim_flop_tab01 ( |
| 103 | .clk_i ( clk_i ), |
| 104 | .rst_ni ( rst_ni ), |
| 105 | .en_i ( z_valid_i ), |
| 106 | .d_i ( {t_a0b0_d, t_a1b1_d} ), |
| 107 | .q_o ( {t_a0b0_q, t_a1b1_q} ) |
| 108 | ); |
| 109 | |
| 110 | assign t_a0b0 = t_a0b0_q; |
| 111 | assign t_a1b1 = t_a1b1_q; |
| 112 | |
| 113 | end else begin : gen_no_inner_domain_regs |
| 114 | // Do not add the optional pipeline registers on the inner-domain terms. This allows to save |
| 115 | // some area in case the multiplier does not need to accept new data in every cycle. However, |
| 116 | // this can cause SCA leakage as during the clock cycle in which new data arrives, the new |
| 117 | // inner-domain terms are integrated with the previous, reshared cross-domain terms. |
| 118 | |
| 119 | assign t_a0b0 = t_a0b0_d; |
| 120 | assign t_a1b1 = t_a1b1_d; |
| 121 | end |
| 122 | |
Pirmin Vogel | e58f674 | 2022-02-21 15:41:50 +0100 | [diff] [blame] | 123 | ///////////////// |
| 124 | // Integration // |
| 125 | ///////////////// |
| 126 | |
| 127 | // Preserve the logic sequence for XOR not to proceed the inner-domain AND. |
| 128 | prim_xor2 #( |
| 129 | .Width ( DW*2 ) |
| 130 | ) u_prim_xor_q01 ( |
| 131 | .in0_i ( {t_a0b0, t_a1b1} ), |
| 132 | .in1_i ( {t0_q, t1_q} ), |
| 133 | .out_o ( {q0_o, q1_o} ) |
| 134 | ); |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 135 | |
Pirmin Vogel | 773de67 | 2022-04-18 14:59:55 +0200 | [diff] [blame] | 136 | // Use intermediate results for remasking computations in another instance in the following |
| 137 | // clock cycle. Use one share only. Directly use output of flops updating with z_valid_i. |
| 138 | // t1_q is obtained by remasking t_a1b0 with z_i. Since z_i is uniformly distributed and |
| 139 | // independent of a1/b0_i, t1_q is also uniformly distributed and independent of a1/b0_i. |
| 140 | // For details, see Lemma 1 in Canright, "A very compact 'perfectly masked' S-box for AES |
| 141 | // (corrected)" available at https://eprint.iacr.org/2009/011.pdf |
| 142 | assign prd_o = t1_q; |
| 143 | |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 144 | // DOM AND should be same as unmasked computation |
Eunchan Kim | c42ce97 | 2020-08-20 14:45:04 -0700 | [diff] [blame] | 145 | // The correct test sequence will be: |
| 146 | // 1. inputs are changed |
Pirmin Vogel | 217328d | 2022-02-21 15:35:59 +0100 | [diff] [blame] | 147 | // 2. check if z_valid_i, |
Pirmin Vogel | cd40a66 | 2022-02-21 18:40:13 +0100 | [diff] [blame] | 148 | // 3. at the next cycle, inputs are still stable (assumption) - only in case Pipeline = 0 |
Eunchan Kim | c42ce97 | 2020-08-20 14:45:04 -0700 | [diff] [blame] | 149 | // 4. and results Q == A & B (assertion) |
| 150 | |
| 151 | // To speed up the FPV process, random value is ready in less than or |
| 152 | // equal to two cycles. |
| 153 | `ASSUME_FPV(RandomReadyInShortTime_A, |
| 154 | $changed(a0_i) || $changed(a1_i) || $changed(b0_i) || $changed(b1_i) |
Pirmin Vogel | 217328d | 2022-02-21 15:35:59 +0100 | [diff] [blame] | 155 | |-> ##[0:2] z_valid_i, |
Eunchan Kim | c42ce97 | 2020-08-20 14:45:04 -0700 | [diff] [blame] | 156 | clk_i, !rst_ni) |
Eunchan Kim | 20614a6 | 2022-06-08 15:10:08 -0700 | [diff] [blame] | 157 | |
| 158 | if (Pipeline == 0) begin: g_assert_stable |
| 159 | // If Pipeline is not set, the computation takes two cycles without flop |
| 160 | // crossing the domain. In this case, the signal should be stable for at |
| 161 | // least two cycles. |
| 162 | `ASSUME(StableTwoCycles_M, |
| 163 | ($changed(a0_i) || $changed(a1_i) || $changed(b0_i) || $changed(b1_i)) |
| 164 | ##[0:$] z_valid_i |=> |
| 165 | $stable(a0_i) && $stable(a1_i) && $stable(b0_i) && $stable(b1_i)) |
| 166 | end |
| 167 | |
Eunchan Kim | c42ce97 | 2020-08-20 14:45:04 -0700 | [diff] [blame] | 168 | `ASSERT(UnmaskedAndMatched_A, |
Eunchan Kim | 20614a6 | 2022-06-08 15:10:08 -0700 | [diff] [blame] | 169 | z_valid_i |=> (q0_o ^ q1_o) == |
| 170 | (($past(a0_i) ^ $past(a1_i)) & ($past(b0_i) ^ $past(b1_i))), |
Eunchan Kim | c42ce97 | 2020-08-20 14:45:04 -0700 | [diff] [blame] | 171 | clk_i, !rst_ni) |
Eunchan Kim | d35dc68 | 2020-05-06 12:27:13 -0700 | [diff] [blame] | 172 | |
| 173 | endmodule |