aegis128.bend
bend-osdev-aead@0.1.0.0 · 308 lines · 50 definitions
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
27import Base
28import bend-osdev-bytes@0.1.0.0/bytes.bend as B
29import bend-osdev-word64@0.1.0.0/word64.bend as W
30import bend-osdev-crypto@0.1.0.0/crypto.bend as Cr
31import bend-osdev-crypto@0.1.0.0/octets.bend as O
32import bend-osdev-aead@0.1.0.0/aead.bend as Ad
33import bend-osdev-aead@0.1.0.0/aesround.bend as R
34
35
36type AdAegisSt is Data:
37 AdAegisSt{s0: R.AdBlk, s1: R.AdBlk, s2: R.AdBlk, s3: R.AdBlk, s4: R.AdBlk}
38
39def ad.ae.update(+sb: R.AdSbox, st: AdAegisSt, +m: R.AdBlk) -> AdAegisSt:
40 match st:
41 case AdAegisSt{+a0, +a1, +a2, +a3, +a4}:
42 AdAegisSt{R.AdAes.round(sb, a4, R.AdBlk.xor(a0, m)), R.AdAes.round(sb, a0, a1), R.AdAes.round(sb, a1, a2), R.AdAes.round(sb, a2, a3), R.AdAes.round(sb, a3, a4)}
43
44
45def ad.ae.z(st: AdAegisSt) -> R.AdBlk:
46 match st:
47 case AdAegisSt{a0, a1, a2, a3, a4}:
48 R.AdBlk.xor(R.AdBlk.xor(a1, a4), R.AdBlk.and(a2, a3))
49
50
51def ad.ae.c0() -> R.AdBlk:
52 R.AdBlk{65794, 50661389, 354563929, 2431220066}
53
54def ad.ae.c1() -> R.AdBlk:
55 R.AdBlk{3678214229, 1841442801, 537997634, 1941252317}
56
57def ad.ae.init.go(n: Nat, +sb: R.AdSbox, +k: R.AdBlk, +kiv: R.AdBlk, st: AdAegisSt) -> AdAegisSt:
58 match n:
59 case 0n:
60 st
61 case 1n+p:
62 ad.ae.init.go(p, sb, k, kiv, ad.ae.update(sb, ad.ae.update(sb, st, k), kiv))
63
64def ad.ae.init(+sb: R.AdSbox, +k: R.AdBlk, +iv: R.AdBlk) -> AdAegisSt:
65 +kiv = R.AdBlk.xor(k, iv)
66 ad.ae.init.go(5n, sb, k, kiv, AdAegisSt{kiv, ad.ae.c1(), ad.ae.c0(), R.AdBlk.xor(k, ad.ae.c0()), R.AdBlk.xor(k, ad.ae.c1())})
67
68
69
70def ad.ae.absorb(+sb: R.AdSbox, ps: List<&2, List<&2, U32>>, st: AdAegisSt) -> AdAegisSt:
71 match ps:
72 case Nil{}:
73 st
74 case Con{p, t}:
75 ad.ae.absorb(sb, t, ad.ae.update(sb, st, R.AdBlk.of_list(p)))
76
77
78
79
80type AdAegisRun is Data:
81 AdAegisRun{st: AdAegisSt, zs: List<&2, U32>, buf: List<&2, U32>, n: Nat}
82
83def ad.ae.run0(+st: AdAegisSt) -> AdAegisRun:
84 AdAegisRun{st, R.AdBlk.to_list(ad.ae.z(st)), Nil{}, 0n}
85
86def ad.ae.rev(xs: List<&2, U32>, acc: List<&2, U32>) -> List<&2, U32>:
87 match xs:
88 case Nil{}:
89 acc
90 case Con{h, t}:
91 ad.ae.rev(t, Con{h, acc})
92
93def ad.ae.tail(xs: List<&2, U32>) -> List<&2, U32>:
94 match xs:
95 case Nil{}:
96 Nil{}
97 case Con{h, t}:
98 t
99
100def ad.ae.head(xs: List<&2, U32>) -> U32:
101 match xs:
102 case Nil{}:
103 0
104 case Con{h, t}:
105 h
106
107def ad.ae.step.pick(full: Bool, +sb: R.AdSbox, st: AdAegisSt, zs: List<&2, U32>, +buf: List<&2, U32>, +n: Nat) -> AdAegisRun:
108 match full:
109 case True{}:
110 ad.ae.run0(ad.ae.update(sb, st, R.AdBlk.of_list(ad.ae.rev(buf, Nil{}))))
111 case False{}:
112 AdAegisRun{st, ad.ae.tail(zs), buf, 1n+n}
113
114
115def ad.ae.step(+sb: R.AdSbox, r: AdAegisRun, x: U32) -> AdAegisRun:
116 match r:
117 case AdAegisRun{st, zs, buf, +n}:
118 ad.ae.step.pick(Nat.is_eq(n, 15n), sb, st, zs, Con{x, buf}, n)
119
120
121def ad.ae.zhead(r: AdAegisRun) -> U32:
122 match r:
123 case AdAegisRun{st, zs, buf, n}:
124 ad.ae.head(zs)
125
126def ad.ae.flush.pick(empty: Bool, +sb: R.AdSbox, st: AdAegisSt, buf: List<&2, U32>) -> AdAegisSt:
127 match empty:
128 case True{}:
129 st
130 case False{}:
131 ad.ae.update(sb, st, R.AdBlk.of_list(ad.ae.rev(buf, Nil{})))
132
133
134def ad.ae.flush(+sb: R.AdSbox, r: AdAegisRun) -> AdAegisSt:
135 match r:
136 case AdAegisRun{st, zs, buf, n}:
137 ad.ae.flush.pick(Nat.is_eq(n, 0n), sb, st, buf)
138
139
140
141
142def ad.ae.eout(xs: List<&2, U32>, +sb: R.AdSbox, +r: AdAegisRun) -> List<&2, U32>:
143 match xs:
144 case Nil{}:
145 Nil{}
146 case Con{+x, t}:
147 Con{B.byte(U32.xor(x, ad.ae.zhead(r))), ad.ae.eout(t, sb, ad.ae.step(sb, r, B.byte(x)))}
148
149def ad.ae.eafter(xs: List<&2, U32>, +sb: R.AdSbox, +r: AdAegisRun) -> AdAegisRun:
150 match xs:
151 case Nil{}:
152 r
153 case Con{+x, t}:
154 ad.ae.eafter(t, sb, ad.ae.step(sb, r, B.byte(x)))
155
156def ad.ae.dout(ys: List<&2, U32>, +sb: R.AdSbox, +r: AdAegisRun) -> List<&2, U32>:
157 match ys:
158 case Nil{}:
159 Nil{}
160 case Con{+y, t}:
161 Con{B.byte(U32.xor(y, ad.ae.zhead(r))), ad.ae.dout(t, sb, ad.ae.step(sb, r, B.byte(U32.xor(y, ad.ae.zhead(r)))))}
162
163def ad.ae.dafter(ys: List<&2, U32>, +sb: R.AdSbox, +r: AdAegisRun) -> AdAegisRun:
164 match ys:
165 case Nil{}:
166 r
167 case Con{+y, t}:
168 ad.ae.dafter(t, sb, ad.ae.step(sb, r, B.byte(U32.xor(y, ad.ae.zhead(r)))))
169
170
171type AdAegisOut is Data:
172 AdAegisOut{r: AdAegisRun, out: List<&2, U32>}
173
174def ad.ae.ego(xs: List<&2, U32>, +sb: R.AdSbox, +r: AdAegisRun, acc: List<&2, U32>) -> AdAegisOut:
175 match xs:
176 case Nil{}:
177 AdAegisOut{r, ad.ae.rev(acc, Nil{})}
178 case Con{+x, t}:
179 ad.ae.ego(t, sb, ad.ae.step(sb, r, B.byte(x)), Con{B.byte(U32.xor(x, ad.ae.zhead(r))), acc})
180
181def ad.ae.dgo(ys: List<&2, U32>, +sb: R.AdSbox, +r: AdAegisRun, acc: List<&2, U32>) -> AdAegisOut:
182 match ys:
183 case Nil{}:
184 AdAegisOut{r, ad.ae.rev(acc, Nil{})}
185 case Con{+y, t}:
186 +p = B.byte(U32.xor(y, ad.ae.zhead(r)))
187 ad.ae.dgo(t, sb, ad.ae.step(sb, r, p), Con{p, acc})
188
189
190def ad.ae.fin.go(n: Nat, +sb: R.AdSbox, +tmp: R.AdBlk, st: AdAegisSt) -> AdAegisSt:
191 match n:
192 case 0n:
193 st
194 case 1n+p:
195 ad.ae.fin.go(p, sb, tmp, ad.ae.update(sb, st, tmp))
196
197def ad.ae.tag(st: AdAegisSt) -> B.Octets:
198 match st:
199 case AdAegisSt{a0, a1, a2, a3, a4}:
200 R.AdBlk.to_octets(R.AdBlk.xor(R.AdBlk.xor(R.AdBlk.xor(a0, a1), R.AdBlk.xor(a2, a3)), a4))
201
202
203
204def ad.ae.w64(n: Nat, acc: W.W64) -> W.W64:
205 match n:
206 case 0n:
207 acc
208 case 1n+p:
209 ad.ae.w64(p, W.W64.add(acc, W.W64.one()))
210
211
212def ad.ae.bits(n: Nat) -> List<&2, U32>:
213 B.le64(W.W64.shl(ad.ae.w64(n, W.W64.zero()), 3n))
214
215def ad.ae.s3(st: AdAegisSt) -> R.AdBlk:
216 match st:
217 case AdAegisSt{a0, a1, a2, a3, a4}:
218 a3
219
220def ad.ae.final(+sb: R.AdSbox, +st: AdAegisSt, +alen: Nat, +mlen: Nat) -> B.Octets:
221 ad.ae.tag(ad.ae.fin.go(7n, sb, R.AdBlk.xor(ad.ae.s3(st), R.AdBlk.of_list(B.append(ad.ae.bits(alen), ad.ae.bits(mlen)))), st))
222
223
224type AdAegisKey is Data:
225 AdAegisKey{k: R.AdBlk, sb: R.AdSbox}
226
227def ad.ae.key.pick(ok: Bool, +o: B.Octets) -> Result<&2, &2, Cr.CrError, AdAegisKey>:
228 match ok:
229 case True{}:
230 Done{AdAegisKey{R.AdBlk.of_octets(o), R.AdAes.sbox()}}
231 case False{}:
232 Fail{Cr.CrBadKeyLength{B.Octets.len(o)}}
233
234def ad.ae.key(+o: B.Octets) -> Result<&2, &2, Cr.CrError, AdAegisKey>:
235 ad.ae.key.pick(Nat.is_eq(B.Octets.len(o), 16n), o)
236
237
238def AdAegis128.key(o: B.Octets) -> Result<&2, &2, Cr.CrError, AdAegisKey>:
239 ad.ae.key(o)
240
241
242
243def ad.ae.start(+sb: R.AdSbox, +k: R.AdBlk, +nonce: B.Octets, +aad: B.Octets) -> AdAegisRun:
244 ad.ae.run0(ad.ae.absorb(sb, O.CrOct.pieces(16n, B.Octets.to_list(aad)), ad.ae.init(sb, k, R.AdBlk.of_octets(nonce))))
245
246def ad.ae.sealed(+sb: R.AdSbox, +aad: B.Octets, +p: B.Octets, o: AdAegisOut) -> B.Octets:
247 match o:
248 case AdAegisOut{r, out}:
249 Ad.AdTag.join(B.Octets.of_list(out), ad.ae.final(sb, ad.ae.flush(sb, r), B.Octets.len(aad), B.Octets.len(p)))
250
251def ad.ae.seal.go(kk: AdAegisKey, +nonce: B.Octets, +aad: B.Octets, +p: B.Octets) -> B.Octets:
252 match kk:
253 case AdAegisKey{+k, +sb}:
254 ad.ae.sealed(sb, aad, p, ad.ae.ego(B.Octets.to_list(p), sb, ad.ae.start(sb, k, nonce, aad), Nil{}))
255
256def ad.ae.nonce(+nonce: B.Octets) -> Result<&2, &2, Cr.CrError, Unit>:
257 Cr.CrError.check(Nat.is_eq(B.Octets.len(nonce), 16n), Cr.CrBadNonceLength{B.Octets.len(nonce)})
258
259def ad.ae.seal(+kk: AdAegisKey, +nonce: B.Octets, +aad: B.Octets, +p: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>:
260 Result.map(&2, &2, Cr.CrError, Unit, B.Octets, u => ad.ae.seal.go(kk, nonce, aad, p), ad.ae.nonce(nonce))
261
262
263def AdAegis128.seal(kk: AdAegisKey, nonce: B.Octets, aad: B.Octets, p: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>:
264 ad.ae.seal(kk, nonce, aad, p)
265
266def ad.ae.tag_of.of(+sb: R.AdSbox, +aad: B.Octets, +c: B.Octets, o: AdAegisOut) -> B.Octets:
267 match o:
268 case AdAegisOut{r, out}:
269 ad.ae.final(sb, ad.ae.flush(sb, r), B.Octets.len(aad), B.Octets.len(c))
270
271def ad.ae.tag_of.go(kk: AdAegisKey, +nonce: B.Octets, +aad: B.Octets, +c: B.Octets) -> B.Octets:
272 match kk:
273 case AdAegisKey{+k, +sb}:
274 ad.ae.tag_of.of(sb, aad, c, ad.ae.dgo(B.Octets.to_list(c), sb, ad.ae.start(sb, k, nonce, aad), Nil{}))
275
276
277def AdAegis128.tag_of(kk: AdAegisKey, +nonce: B.Octets, +aad: B.Octets, +c: B.Octets) -> B.Octets:
278 ad.ae.tag_of.go(kk, nonce, aad, c)
279
280def ad.ae.plain.of(o: AdAegisOut) -> B.Octets:
281 match o:
282 case AdAegisOut{r, out}:
283 B.Octets.of_list(out)
284
285def ad.ae.plain(kk: AdAegisKey, +nonce: B.Octets, +aad: B.Octets, +c: B.Octets) -> B.Octets:
286 match kk:
287 case AdAegisKey{+k, +sb}:
288 ad.ae.plain.of(ad.ae.dgo(B.Octets.to_list(c), sb, ad.ae.start(sb, k, nonce, aad), Nil{}))
289
290def ad.ae.check(ok: Bool, +p: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>:
291 match ok:
292 case True{}:
293 Done{p}
294 case False{}:
295 Fail{Cr.CrTagMismatch{}}
296
297def ad.ae.open.go(+kk: AdAegisKey, +nonce: B.Octets, +aad: B.Octets, s: Ad.AdSplit) -> Result<&2, &2, Cr.CrError, B.Octets>:
298 match s:
299 case Ad.AdSplit{+c, t}:
300 ad.ae.check(Ad.AdTag.is_eq(AdAegis128.tag_of(kk, nonce, aad, c), t), ad.ae.plain(kk, nonce, aad, c))
301
302def ad.ae.open(+kk: AdAegisKey, +nonce: B.Octets, +aad: B.Octets, +c: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>:
303 Result.bind(&2, &2, Cr.CrError, Unit, B.Octets, ad.ae.nonce(nonce), u => Result.bind(&2, &2, Cr.CrError, Ad.AdSplit, B.Octets, Ad.AdTag.split(16n, c), s => ad.ae.open.go(kk, nonce, aad, s)))
304
305
306
307def AdAegis128.open(kk: AdAegisKey, nonce: B.Octets, aad: B.Octets, c: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>:
308 ad.ae.open(kk, nonce, aad, c)