src/crypto/argon2/argon2.bend
bend-collections-laws-crypto@1.0.0.0 · 366 lines · 46 definitions
1import Base
2import bend-collections-laws-crypto@1.0.0.0/src/math/w64.bend as X
3import bend-collections-laws-crypto@1.0.0.0/src/crypto/blake/blake2b/types.bend as T
4import bend-collections-laws-crypto@1.0.0.0/src/crypto/blake/blake2b/sized.bend as H
5import bend-collections-laws-crypto@1.0.0.0/src/crypto/argon2/types.bend as A
6import bend-collections-laws-crypto@1.0.0.0/src/crypto/argon2/blamka.bend as G
7import bend-collections-laws-crypto@1.0.0.0/src/crypto/argon2/sub.bend as SB
8import bend-collections-laws-crypto@1.0.0.0/src/crypto/argon2/memory.bend as M
9
10
11
12
13
14
15def cat(xs: List<&2, U32>, ys: List<&2, U32>) -> List<&2, U32>:
16 List.append(&2, U32, xs, ys)
17
18def len(xs: List<&2, U32>) -> Nat:
19 List.length(&2, U32, xs)
20
21
22def le32(+n: Nat) -> List<&2, U32>:
23 [U32.from_nat(Nat.mod(n, 256n)), U32.from_nat(Nat.mod(Nat.div(n, 256n), 256n)), U32.from_nat(Nat.mod(Nat.div(n, 65536n), 256n)), U32.from_nat(Nat.div(n, 16777216n))]
24
25
26
27
28
29
30
31def hp_go(n: Nat, v: List<&2, U32>, +last: Nat) -> List<&2, U32>:
32 match n v:
33 case _ Nil{}:
34 Nil{}
35 case 0n +x <> +r:
36 cat(List.take(&2, U32, x <> r, 32n), H.hash(last, x <> r))
37 case 1n+p +x <> +r:
38 cat(List.take(&2, U32, x <> r, 32n), hp_go(p, H.hash(64n, x <> r), last))
39
40def hp_pick(+tl: Nat, +x: List<&2, U32>, short: Bool) -> List<&2, U32>:
41 match short:
42 case True{}:
43 H.hash(tl, x)
44 case False{}:
45 +r = Nat.sub(Nat.div(Nat.add(tl, 31n), 32n), 2n)
46 hp_go(Nat.sub(r, 1n), H.hash(64n, x), Nat.sub(tl, Nat.mul(32n, r)))
47
48
49def hprime(+tl: Nat, a: List<&2, U32>) -> List<&2, U32>:
50 hp_pick(tl, cat(le32(tl), a), Nat.is_le(tl, 64n))
51
52
53def h0(+p: Nat, +tl: Nat, +m: Nat, +t: Nat, +pw: List<&2, U32>, +salt: List<&2, U32>, +key: List<&2, U32>, +ad: List<&2, U32>) -> List<&2, U32>:
54 H.hash(64n, cat(le32(p), cat(le32(tl), cat(le32(m), cat(le32(t), cat(le32(19n), cat(le32(2n), cat(le32(len(pw)), cat(pw, cat(le32(len(salt)), cat(salt, cat(le32(len(key)), cat(key, cat(le32(len(ad)), ad))))))))))))))
55
56
57
58
59def block_of(bs: List<&2, U32>) -> A.Block:
60 SB.rows8(H.words(bs))
61
62def state_bytes(v: T.State) -> List<&2, U32>:
63 match v:
64 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15}:
65 List.concat(&2, U32, [H.lane_bytes(x0), H.lane_bytes(x1), H.lane_bytes(x2), H.lane_bytes(x3), H.lane_bytes(x4), H.lane_bytes(x5), H.lane_bytes(x6), H.lane_bytes(x7), H.lane_bytes(x8), H.lane_bytes(x9), H.lane_bytes(x10), H.lane_bytes(x11), H.lane_bytes(x12), H.lane_bytes(x13), H.lane_bytes(x14), H.lane_bytes(x15)])
66
67
68def block_bytes(b: A.Block) -> List<&2, U32>:
69 match b:
70 case A.B{r0, r1, r2, r3, r4, r5, r6, r7}:
71 List.concat(&2, U32, [state_bytes(r0), state_bytes(r1), state_bytes(r2), state_bytes(r3), state_bytes(r4), state_bytes(r5), state_bytes(r6), state_bytes(r7)])
72
73def row_at(b: A.Block, +i: Nat) -> T.State:
74 match b i:
75 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} 0n:
76 r0
77 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} 1n:
78 r1
79 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} 2n:
80 r2
81 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} 3n:
82 r3
83 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} 4n:
84 r4
85 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} 5n:
86 r5
87 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} 6n:
88 r6
89 case A.B{r0, r1, r2, r3, r4, r5, r6, r7} _:
90 r7
91
92def at(v: T.State, +j: Nat) -> T.Lane:
93 match v j:
94 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 0n:
95 x0
96 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 1n:
97 x1
98 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 2n:
99 x2
100 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 3n:
101 x3
102 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 4n:
103 x4
104 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 5n:
105 x5
106 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 6n:
107 x6
108 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 7n:
109 x7
110 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 8n:
111 x8
112 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 9n:
113 x9
114 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 10n:
115 x10
116 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 11n:
117 x11
118 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 12n:
119 x12
120 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 13n:
121 x13
122 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 14n:
123 x14
124 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} 15n:
125 x15
126 case T.V{x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15} _:
127 T.W{0, 0}
128
129
130def lane(+b: A.Block, +n: Nat) -> T.Lane:
131 at(row_at(b, Nat.div(n, 16n)), Nat.mod(n, 16n))
132
133
134
135def hi(x: T.Lane) -> U32:
136 match x:
137 case T.W{l, h}:
138 h
139
140def small(+x: Nat) -> T.Lane:
141 T.W{U32.from_nat(x), 0}
142
143
144def input_of(+r: Nat, +l: Nat, +s: Nat, +mm: Nat, +t: Nat, +ctr: Nat) -> A.Block:
145 A.B{T.V{small(r), small(l), small(s), small(mm), small(t), small(2n), small(ctr), T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}, T.V{T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}, T.V{T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}, T.V{T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}, T.V{T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}, T.V{T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}, T.V{T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}, T.V{T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}, T.W{0, 0}}}
146
147
148
149def input_block(r: Nat, +l: Nat, +s: Nat, +mm: Nat, +t: Nat, +ctr: Nat) -> A.Block:
150 match r:
151 case 0n:
152 input_of(0n, l, s, mm, t, ctr)
153 case 1n+x:
154 input_of(1n+x, l, s, mm, t, ctr)
155
156
157def addresses(+r: Nat, +l: Nat, +s: Nat, +mm: Nat, +t: Nat, +ctr: Nat) -> A.Block:
158 G.compress(G.zero(), G.compress(G.zero(), input_block(r, l, s, mm, t, ctr)))
159
160
161
162def regen(need: Bool, addr: A.Block, +r: Nat, +l: Nat, +s: Nat, +mm: Nat, +t: Nat, +idx: Nat) -> A.Block:
163 match need:
164 case True{}:
165 addresses(r, l, s, mm, t, Nat.add(Nat.div(idx, 128n), 1n))
166 case False{}:
167 addr
168
169
170def area_base(r0: Bool, +s: Nat, +sl: Nat, +q: Nat) -> Nat:
171 match r0:
172 case True{}:
173 Nat.mul(s, sl)
174 case False{}:
175 Nat.sub(q, sl)
176
177def area_other(+base: Nat, zero: Bool) -> Nat:
178 match zero:
179 case True{}:
180 Nat.sub(base, 1n)
181 case False{}:
182 base
183
184def area(+base: Nat, +idx: Nat, same: Bool) -> Nat:
185 match same:
186 case True{}:
187 Nat.sub(Nat.add(base, idx), 1n)
188 case False{}:
189 area_other(base, Nat.is_eq(idx, 0n))
190
191
192def rel(+w: Nat, +j1: U32) -> Nat:
193 +x = X.hi(X.mul32(j1, j1))
194 Nat.sub(Nat.sub(w, 1n), U32.to_nat(X.hi(X.mul32(U32.from_nat(w), x))))
195
196def start_last(+s: Nat, +sl: Nat, last: Bool) -> Nat:
197 match last:
198 case True{}:
199 0n
200 case False{}:
201 Nat.mul(Nat.add(s, 1n), sl)
202
203
204
205def start(r0: Bool, +s: Nat, +sl: Nat) -> Nat:
206 match r0:
207 case True{}:
208 0n
209 case False{}:
210 start_last(s, sl, Nat.is_eq(s, 3n))
211
212def ref_lane(forced: Bool, +l: Nat, +j2: U32, +p: Nat) -> Nat:
213 match forced:
214 case True{}:
215 l
216 case False{}:
217 Nat.mod(U32.to_nat(j2), p)
218
219def prev_index(+l: Nat, +q: Nat, +j: Nat, first: Bool) -> Nat:
220 match first:
221 case True{}:
222 Nat.add(Nat.mul(l, q), Nat.sub(q, 1n))
223 case False{}:
224 Nat.sub(Nat.add(Nat.mul(l, q), j), 1n)
225
226def pick(indep: Bool, +addr: A.Block, +idx: Nat, +prev: A.Block) -> T.Lane:
227 match indep:
228 case True{}:
229 lane(addr, Nat.mod(idx, 128n))
230 case False{}:
231 lane(prev, 0n)
232
233
234
235def store_xor(+cur: Nat, +prev: A.Block, +refb: A.Block, pair: Array<U32> & A.Block) -> Array<U32>:
236 (a, old) = pair
237 M.set(cur, G.compress_xor(prev, refb, old), a)
238
239
240def store(r0: Bool, +cur: Nat, +prev: A.Block, +refb: A.Block, a: Array<U32>) -> Array<U32>:
241 match r0:
242 case True{}:
243 M.set(cur, G.compress(prev, refb), a)
244 case False{}:
245 store_xor(cur, prev, refb, M.get(cur, a))
246
247def with_ref(r0: Bool, +cur: Nat, +prev: A.Block, pair: Array<U32> & A.Block) -> Array<U32>:
248 (a, +refb) = pair
249 store(r0, cur, prev, refb, a)
250
251
252def step(+r: Nat, +l: Nat, +s: Nat, +idx: Nat, +p: Nat, +q: Nat, +sl: Nat, +cur: Nat, +indep: Bool, +addr: A.Block, pair: Array<U32> & A.Block) -> Array<U32>:
253 (a, +prev) = pair
254 +r0 = Nat.is_eq(r, 0n)
255 +pr = pick(indep, addr, idx, prev)
256 +rl = ref_lane(Bool.and(r0, Nat.is_eq(s, 0n)), l, hi(pr), p)
257 +w = area(area_base(r0, s, sl, q), idx, Nat.is_eq(rl, l))
258 +ri = Nat.mod(Nat.add(start(r0, s, sl), rel(w, G.lo(pr))), q)
259 with_ref(r0, cur, prev, M.get(Nat.add(Nat.mul(rl, q), ri), a))
260
261
262def seg_go(n: Nat, +idx: Nat, first: Bool, addr: A.Block, a: Array<U32>, +r: Nat, +l: Nat, +s: Nat, +p: Nat, +q: Nat, +sl: Nat, +mm: Nat, +t: Nat, +indep: Bool) -> Array<U32>:
263 match n:
264 case 0n:
265 a
266 case 1n+rest:
267 +addr2 = regen(Bool.and(indep, Bool.or(first, Nat.is_eq(Nat.mod(idx, 128n), 0n))), addr, r, l, s, mm, t, idx)
268 +j = Nat.add(Nat.mul(s, sl), idx)
269 +cur = Nat.add(Nat.mul(l, q), j)
270 seg_go(rest, Nat.add(idx, 1n), False{}, addr2, step(r, l, s, idx, p, q, sl, cur, indep, addr2, M.get(prev_index(l, q, j, Nat.is_eq(j, 0n)), a)), r, l, s, p, q, sl, mm, t, indep)
271
272def start_index(first: Bool) -> Nat:
273 match first:
274 case True{}:
275 2n
276 case False{}:
277 0n
278
279
280
281def segment(+r: Nat, +s: Nat, +l: Nat, +p: Nat, +q: Nat, +sl: Nat, +mm: Nat, +t: Nat, a: Array<U32>) -> Array<U32>:
282 +r0 = Nat.is_eq(r, 0n)
283 +st = start_index(Bool.and(r0, Nat.is_eq(s, 0n)))
284 seg_go(Nat.sub(sl, st), st, True{}, G.zero(), a, r, l, s, p, q, sl, mm, t, Bool.and(r0, Nat.is_lt(s, 2n)))
285
286def lanes_go(n: Nat, +l: Nat, +r: Nat, +s: Nat, +p: Nat, +q: Nat, +sl: Nat, +mm: Nat, +t: Nat, a: Array<U32>) -> Array<U32>:
287 match n:
288 case 0n:
289 a
290 case 1n+rest:
291 lanes_go(rest, Nat.add(l, 1n), r, s, p, q, sl, mm, t, segment(r, s, l, p, q, sl, mm, t, a))
292
293def slices_go(n: Nat, +s: Nat, +r: Nat, +p: Nat, +q: Nat, +sl: Nat, +mm: Nat, +t: Nat, a: Array<U32>) -> Array<U32>:
294 match n:
295 case 0n:
296 a
297 case 1n+rest:
298 slices_go(rest, Nat.add(s, 1n), r, p, q, sl, mm, t, lanes_go(p, 0n, r, s, p, q, sl, mm, t, a))
299
300def passes_go(n: Nat, +r: Nat, +p: Nat, +q: Nat, +sl: Nat, +mm: Nat, +t: Nat, a: Array<U32>) -> Array<U32>:
301 match n:
302 case 0n:
303 a
304 case 1n+rest:
305 passes_go(rest, Nat.add(r, 1n), p, q, sl, mm, t, slices_go(4n, 0n, r, p, q, sl, mm, t, a))
306
307
308def init_go(n: Nat, +l: Nat, +q: Nat, +hh: List<&2, U32>, a: Array<U32>) -> Array<U32>:
309 match n:
310 case 0n:
311 a
312 case 1n+rest:
313 +b0 = block_of(hprime(1024n, cat(hh, cat(le32(0n), le32(l)))))
314 +b1 = block_of(hprime(1024n, cat(hh, cat(le32(1n), le32(l)))))
315 init_go(rest, Nat.add(l, 1n), q, hh, M.set(Nat.add(Nat.mul(l, q), 1n), b1, M.set(Nat.mul(l, q), b0, a)))
316
317
318
319def final_go(n: Nat, +l: Nat, +q: Nat, c: A.Block, pair: Array<U32> & A.Block) -> A.Block:
320 match n pair:
321 case 0n Tuple{a, b}:
322 G.xor(c, b)
323 case 1n+rest Tuple{a, b}:
324 final_go(rest, Nat.add(l, 1n), q, G.xor(c, b), M.get(Nat.add(Nat.mul(Nat.add(l, 1n), q), Nat.sub(q, 1n)), a))
325
326
327
328
329
330
331def valid(+pw: List<&2, U32>, +salt: List<&2, U32>, +key: List<&2, U32>, +ad: List<&2, U32>, +t: Nat, +m: Nat, +p: Nat, +tl: Nat) -> Bool:
332 Bool.and(Bool.and(Bool.and(Nat.is_le(1n, p), Nat.is_le(p, 16777215n)), Bool.and(Nat.is_le(4n, tl), Nat.is_le(tl, 4294967295n))),
333 Bool.and(Bool.and(Bool.and(Nat.is_le(Nat.mul(8n, p), m), Nat.is_le(m, 4294967295n)), Bool.and(Nat.is_le(1n, t), Nat.is_le(t, 4294967295n))),
334 Bool.and(Bool.and(Nat.is_le(8n, len(salt)), Nat.is_le(len(salt), 4294967295n)), Bool.and(Nat.is_le(len(pw), 4294967295n), Bool.and(Nat.is_le(len(key), 4294967295n), Nat.is_le(len(ad), 4294967295n))))))
335
336
337def blocks(+m: Nat, +p: Nat) -> Nat:
338 Nat.mul(Nat.mul(4n, p), Nat.div(m, Nat.mul(4n, p)))
339
340
341
342def fits(+m: Nat, +p: Nat) -> Bool:
343 Nat.is_le(M.levels(blocks(m, p)), 23n)
344
345
346def run(+pw: List<&2, U32>, +salt: List<&2, U32>, +key: List<&2, U32>, +ad: List<&2, U32>, +t: Nat, +m: Nat, +p: Nat, +tl: Nat) -> List<&2, U32>:
347 +mm = blocks(m, p)
348 +q = Nat.div(mm, p)
349 +sl = Nat.div(q, 4n)
350 +k = M.levels(mm)
351 +hh = h0(p, tl, m, t, pw, salt, key, ad)
352 a = passes_go(t, 0n, p, q, sl, mm, t, init_go(p, 0n, q, hh, M.new(k)))
353 hprime(tl, block_bytes(final_go(Nat.sub(p, 1n), 0n, q, G.zero(), M.get(Nat.sub(q, 1n), a))))
354
355def checked(ok: Bool, +pw: List<&2, U32>, +salt: List<&2, U32>, +key: List<&2, U32>, +ad: List<&2, U32>, +t: Nat, +m: Nat, +p: Nat, +tl: Nat) -> Maybe<&2, List<&2, U32>>:
356 match ok:
357 case True{}:
358 Some{run(pw, salt, key, ad, t, m, p, tl)}
359 case False{}:
360 None{}
361
362
363
364
365def argon2id(+pw: List<&2, U32>, +salt: List<&2, U32>, +key: List<&2, U32>, +ad: List<&2, U32>, +t: Nat, +m: Nat, +p: Nat, +tl: Nat) -> Maybe<&2, List<&2, U32>>:
366 checked(Bool.and(valid(pw, salt, key, ad, t, m, p, tl), fits(m, p)), pw, salt, key, ad, t, m, p, tl)