blob: b45db9ae48afbdcecc2151c4f0d73db2c6c255ec [file] [log] [blame]
Eunchan Kimd35dc682020-05-06 12:27:13 -07001// 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
28module prim_dom_and_2share #(
Pirmin Vogelcd40a662022-02-21 18:40:13 +010029 parameter int DW = 64, // Input width
30 parameter bit Pipeline = 1'b0 // Enable full pipelining
Eunchan Kimd35dc682020-05-06 12:27:13 -070031) (
32 input clk_i,
Eunchan Kim0210f992020-08-13 18:02:44 -070033 input rst_ni,
Eunchan Kimd35dc682020-05-06 12:27:13 -070034
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 Vogel217328d2022-02-21 15:35:59 +010039 input z_valid_i, // random number input validity
40 input [DW-1:0] z_i, // random number
Eunchan Kimd35dc682020-05-06 12:27:13 -070041
42 output logic [DW-1:0] q0_o, // share0 of q
Pirmin Vogel773de672022-04-18 14:59:55 +020043 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 Kimd35dc682020-05-06 12:27:13 -070045);
46
47 logic [DW-1:0] t0_d, t0_q, t1_d, t1_q;
Pirmin Vogelcd40a662022-02-21 18:40:13 +010048 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 Kimd35dc682020-05-06 12:27:13 -070051
Pirmin Vogele58f6742022-02-21 15:41:50 +010052 /////////////////
53 // Calculation //
54 /////////////////
55 // Inner-domain terms
Pirmin Vogelcd40a662022-02-21 18:40:13 +010056 assign t_a0b0_d = a0_i & b0_i;
57 assign t_a1b1_d = a1_i & b1_i;
Pirmin Vogele58f6742022-02-21 15:41:50 +010058
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 Vogelcd40a662022-02-21 18:40:13 +010089 /////////////////////////
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 Vogele58f6742022-02-21 15:41:50 +0100123 /////////////////
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 Kimd35dc682020-05-06 12:27:13 -0700135
Pirmin Vogel773de672022-04-18 14:59:55 +0200136 // 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 Kimd35dc682020-05-06 12:27:13 -0700144 // DOM AND should be same as unmasked computation
Eunchan Kimc42ce972020-08-20 14:45:04 -0700145 // The correct test sequence will be:
146 // 1. inputs are changed
Pirmin Vogel217328d2022-02-21 15:35:59 +0100147 // 2. check if z_valid_i,
Pirmin Vogelcd40a662022-02-21 18:40:13 +0100148 // 3. at the next cycle, inputs are still stable (assumption) - only in case Pipeline = 0
Eunchan Kimc42ce972020-08-20 14:45:04 -0700149 // 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 Vogel217328d2022-02-21 15:35:59 +0100155 |-> ##[0:2] z_valid_i,
Eunchan Kimc42ce972020-08-20 14:45:04 -0700156 clk_i, !rst_ni)
Eunchan Kim20614a62022-06-08 15:10:08 -0700157
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 Kimc42ce972020-08-20 14:45:04 -0700168 `ASSERT(UnmaskedAndMatched_A,
Eunchan Kim20614a62022-06-08 15:10:08 -0700169 z_valid_i |=> (q0_o ^ q1_o) ==
170 (($past(a0_i) ^ $past(a1_i)) & ($past(b0_i) ^ $past(b1_i))),
Eunchan Kimc42ce972020-08-20 14:45:04 -0700171 clk_i, !rst_ni)
Eunchan Kimd35dc682020-05-06 12:27:13 -0700172
173endmodule