-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathAsconCipher.bsv
214 lines (179 loc) · 7.58 KB
/
AsconCipher.bsv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package AsconCipher;
import Vector :: *;
import Printf :: * ;
import BluelightUtils :: *;
import CryptoCore :: *;
import AsconRound :: *;
import LwcApi :: *;
function Action dump_state(String msg, AsconState s);
action
$write("%24.24s: ", msg);
for (Integer i = 0; i < 5; i = i + 1)
$write(" x%1.1d=%h", i, s[i]);
$display("");
endaction
endfunction
typedef enum {
Idle,
LoadKey,
Absorb,
Permute,
Squeeze
} State deriving (Bits, Eq, FShow);
typedef TMul#(RateWords,8) BlockBytes;
typedef BlockOfSize#(BlockBytes) Block;
typedef ByteValidsOfSize#(BlockBytes) ByteValids;
function Vector#(n_words, AsconWord) bytesToWords(Vector#(n_bytes, Byte) bytes) provisos(Mul#(n_words,8,n_bytes));
Vector#(n_words, AsconWord) x = unpack(pack(bytes));
return map(swapEndian, x);
endfunction
function AsconWord bytesToWord(Vector#(8, Byte) bytes);
return swapEndian(pack(bytes));
endfunction
function Vector#(n_bytes, Byte) wordsToBytes(Vector#(n_words, AsconWord) words) provisos(Mul#(n_words,8,n_bytes));
Vector#(n_words, AsconWord) x = map(swapEndian, words);
return unpack(pack(x));
endfunction
typedef 128 KeyBits;
typedef 128 NonceBits;
typedef TDiv#(KeyBits, 32) NumKeyWords;
interface CipherIfc#(numeric type n_bytes, type flags_type);
// optional operation-specific initialization
method Action start (OpFlags op);
// load key into internal key buffer
method Action loadKey (CoreWord word, Bool last);
// block in/out
method ActionValue#(BlockOfSize#(n_bytes)) absorb (BlockOfSize#(n_bytes) block, ByteValidsOfSize#(n_bytes) valids, Bool last, flags_type flags);
// block out
method ActionValue#(BlockOfSize#(8)) squeeze;
endinterface
typedef struct {
Bool npub; // nonce public
Bool ad; // associated data
Bool emptyAD; // empty associated data
Bool ct; // ciphertext
Bool ptct; // PT or CT
Bool hm; // hash message
Bool ptCtHm; // PT or CT or HM
Bool ptCtAd; // PT or CT or AD
} Flags deriving(Bits, Eq, FShow);
module mkAsconCipher #(parameter Bool ascon128a) (CipherIfc#(BlockBytes, Flags)) provisos (Mul#(UnrollFactor, pa_cycles, PaRounds), Mul#(UnrollFactor, pb_cycles, PbRounds));
messageM(sprintf("\n\n*** Ascon-%s UnrollFactor=%d PaRounds=%d PbRounds=%d ***\n\n", ascon128a ? "128A" : "128", valueOf(UnrollFactor), valueOf(PaRounds), valueOf(PbRounds)));
Reg#(AsconState) asconState <- mkRegU;
let state <- mkReg(Idle);
Reg#(State) postPermuteState <- mkRegU;
Reg#(Vector#(NumKeyWords, CoreWord)) keyStore <- mkRegU;
Reg#(Bit#(TLog#(pa_cycles))) roundCounter <- mkRegU;
Reg#(RoundConstant) roundConstant <- mkRegU;
Reg#(Bit#(2)) squeezeCounter <- mkRegU; // 2 bits if supports hash, o/w 1 bit
Reg#(Bit#(TLog#(TDiv#(NonceBits, TMul#(BlockBytes, 8))))) loadNonceCounter <- mkRegU;
Reg#(Bool) squeezeHash <- mkRegU;
Reg#(Bool) first_block <- mkRegU; // first block of a type
Vector#(2, AsconWord) storedKey = reverse(unpack(pack(reverse(keyStore))));
let rateWords = valueOf(RateWords);
(* fire_when_enabled, no_implicit_conditions *)
rule rl_permutation if (state == Permute);
match {.nxtState, .nxtRC} = permutation(asconState, roundConstant);
asconState <= nxtState;
roundConstant <= nxtRC;
roundCounter <= roundCounter + 1;
if (roundCounter == fromInteger(valueOf(pa_cycles) - 1))
state <= postPermuteState;
endrule
function AsconWord getIV(Bool hash);
Byte r = {fromInteger(rateWords), 6'b0};
Byte a = fromInteger(valueOf(PaRounds));
Byte b = hash ? 0 : fromInteger(valueOf(PbRounds));
return {pack(!hash), 7'b0, r, a, b, 23'b0, pack(hash), 8'b0};
endfunction
function AsconState keyNonceInit(Block npubBlock, Vector#(2, AsconWord) ks);
// Npub_0: previously copied if rateWords == 1
AsconState s = asconState;
s[0] = getIV(False);
s[1] = ks[0];
s[2] = ks[1];
let npub = bytesToWords(npubBlock);
for (Integer i = 0; i < rateWords; i = i + 1)
s[5 - rateWords + i] = npub[i];
return s;
endfunction
// Must be called before any operation
method Action start (OpFlags op) if (state == Idle);
if(op.hash) begin
asconState <= unpack(pack(zeroExtend(getIV(True))));
roundConstant <= initRC(False);
end
state <= op.hash ? Permute : op.new_key ? LoadKey : Absorb;
postPermuteState <= Absorb;
roundCounter <= 0;
loadNonceCounter <= 0;
squeezeCounter <= 0;
first_block <= True;
endmethod
method Action loadKey (CoreWord word, Bool last) if (state == LoadKey);
keyStore <= shiftInAtN(keyStore, swapEndian(pack(word)));
if (last)
state <= Absorb;
endmethod
method ActionValue#(Block) absorb (Block block, ByteValids valids, Bool last, Flags flags) if (state == Absorb);
Block rateBlock = wordsToBytes(take(asconState));
Block xoredBlock = unpack(pack(block) ^ pack(rateBlock));
AsconState absorbedState = asconState;
Block ctBlock = xoredBlock;
for (Integer i = 0; i < valueOf(BlockBytes); i = i + 1)
if (valids[i]) ctBlock[i] = block[i];
if (last || flags.npub)
first_block <= True;
else
first_block <= False;
// TODO move to flags:
let firstAD = flags.ad && first_block;
let firstPtCt = flags.ptct && first_block;
let lastPtCt = flags.ptct && last;
let lastPtCtHash = last && flags.ptCtHm;
let pb = flags.ptCtAd && !(flags.ptct && last);
if (!flags.emptyAD)
for (Integer i = 0; i < rateWords; i = i + 1)
absorbedState[i] = bytesToWord(flags.ct ? takeAt(i*8, ctBlock) : takeAt(i*8, xoredBlock)); // FIXME
if (lastPtCt) begin
for (Integer i = 0; i < 2; i = i + 1)
absorbedState[rateWords + i] = asconState[rateWords + i] ^ storedKey[i];
end
if (firstAD) begin
for (Integer i = 0; i < 2; i = i + 1)
absorbedState[3+i] = asconState[3+i] ^ storedKey[i];
end
absorbedState[4][0] = absorbedState[4][0] ^ pack(firstPtCt); // last bit of state
if (flags.npub) begin
loadNonceCounter <= loadNonceCounter + 1;
if (loadNonceCounter == 1) begin
asconState <= keyNonceInit(block, storedKey);
state <= Permute;
end else
asconState[3] <= bytesToWord(take(block)); // Npub_0
end else begin
asconState <= absorbedState;
if (!flags.emptyAD)
state <= Permute;
end
roundConstant <= initRC(pb);
roundCounter <= pb ? fromInteger(valueOf(pa_cycles) - valueOf(pb_cycles)) : 0;
postPermuteState <= lastPtCtHash ? Squeeze : Absorb;
squeezeHash <= flags.hm;
return xoredBlock;
endmethod
method ActionValue#(BlockOfSize#(8)) squeeze if (state == Squeeze);
squeezeCounter <= squeezeCounter + 1;
if (squeezeCounter[0] == 1'b1 && (!squeezeHash || squeezeCounter[1] == 1'b1))
state <= Idle;
else if (squeezeHash)
state <= Permute;
postPermuteState <= Squeeze;
roundCounter <= 0;
roundConstant <= initRC(False); // P_a for hash
return unpack(
swapEndian(squeezeHash ? asconState[0] : asconState[squeezeCounter[0] == 1'b1 ? 4 : 3] ^ storedKey[squeezeCounter[0]])
);
endmethod
endmodule
endpackage