chiark / gitweb /
t/t-algorithms.py: Add tests for the new `KeySZ.pad' method.
[catacomb-python] / t / t-algorithms.py
CommitLineData
553d59fe
MW
1### -*- mode: python, coding: utf-8 -*-
2###
3### Test symmetric algorithms
4###
5### (c) 2019 Straylight/Edgeware
6###
7
8###----- Licensing notice ---------------------------------------------------
9###
10### This file is part of the Python interface to Catacomb.
11###
12### Catacomb/Python is free software: you can redistribute it and/or
13### modify it under the terms of the GNU General Public License as
14### published by the Free Software Foundation; either version 2 of the
15### License, or (at your option) any later version.
16###
17### Catacomb/Python is distributed in the hope that it will be useful, but
18### WITHOUT ANY WARRANTY; without even the implied warranty of
19### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20### General Public License for more details.
21###
22### You should have received a copy of the GNU General Public License
23### along with Catacomb/Python. If not, write to the Free Software
24### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25### USA.
26
27###--------------------------------------------------------------------------
28### Imported modules.
29
30import catacomb as C
31import unittest as U
32import testutils as T
33
34###--------------------------------------------------------------------------
35### Utilities.
36
37def bad_key_size(ksz):
38 if isinstance(ksz, C.KeySZAny): return None
39 elif isinstance(ksz, C.KeySZRange):
40 if ksz.mod != 1: return ksz.min + 1
41 elif ksz.max != 0: return ksz.max + 1
42 elif ksz.min != 0: return ksz.min - 1
43 else: return None
44 elif isinstance(ksz, C.KeySZSet):
45 for sz in sorted(ksz.set):
46 if sz + 1 not in ksz.set: return sz + 1
47 assert False, "That should have worked."
48 else:
49 return None
50
51def different_key_size(ksz, sz):
52 if isinstance(ksz, C.KeySZAny): return sz + 1
53 elif isinstance(ksz, C.KeySZRange):
54 if sz > ksz.min: return sz - ksz.mod
55 elif ksz.max == 0 or sz < ksz.max: return sz + ksz.mod
56 else: return None
57 elif isinstance(ksz, C.KeySZSet):
58 for sz1 in sorted(ksz.set):
59 if sz != sz1: return sz1
60 return None
61 else:
62 return None
63
64class HashBufferTestMixin (U.TestCase):
65 """Mixin class for testing all of the various `hash...' methods."""
66
67 def check_hashbuffer_hashn(me, w, bigendp, makefn, hashfn):
68 """Check `hashuN'."""
69
70 ## Check encoding an integer.
71 h0, donefn0 = makefn(w + 2)
72 hashfn(h0.hashu8(0x00), T.bytes_as_int(w, bigendp)).hashu8(w + 1)
73 h1, donefn1 = makefn(w + 2)
74 h1.hash(T.span(w + 2))
75 me.assertEqual(donefn0(), donefn1())
76
77 ## Check overflow detection.
78 h0, _ = makefn(w)
79 me.assertRaises((OverflowError, ValueError),
80 hashfn, h0, 1 << 8*w)
81
82 def check_hashbuffer_bufn(me, w, bigendp, makefn, hashfn):
83 """Check `hashbufN'."""
84
85 ## Go through a number of different sizes.
86 for n in [0, 1, 7, 8, 19, 255, 12345, 65535, 123456]:
87 if n >= 1 << 8*w: continue
88 h0, donefn0 = makefn(2 + w + n)
89 hashfn(h0.hashu8(0x00), T.span(n)).hashu8(0xff)
90 h1, donefn1 = makefn(2 + w + n)
91 h1.hash(T.prep_lenseq(w, n, bigendp, True))
92 me.assertEqual(donefn0(), donefn1())
93
94 ## Check blocks which are too large for the length prefix.
95 if w <= 3:
96 n = 1 << 8*w
97 h0, _ = makefn(w + n)
98 me.assertRaises((ValueError, OverflowError, TypeError),
99 hashfn, h0, C.ByteString.zero(n))
100
101 def check_hashbuffer(me, makefn):
102 """Test the various `hash...' methods."""
103
104 ## Check `hashuN'.
105 me.check_hashbuffer_hashn(1, True, makefn, lambda h, n: h.hashu8(n))
106 me.check_hashbuffer_hashn(2, True, makefn, lambda h, n: h.hashu16(n))
107 me.check_hashbuffer_hashn(2, True, makefn, lambda h, n: h.hashu16b(n))
108 me.check_hashbuffer_hashn(2, False, makefn, lambda h, n: h.hashu16l(n))
109 if hasattr(makefn(0)[0], "hashu24"):
110 me.check_hashbuffer_hashn(3, True, makefn, lambda h, n: h.hashu24(n))
111 me.check_hashbuffer_hashn(3, True, makefn, lambda h, n: h.hashu24b(n))
112 me.check_hashbuffer_hashn(3, False, makefn, lambda h, n: h.hashu24l(n))
113 me.check_hashbuffer_hashn(4, True, makefn, lambda h, n: h.hashu32(n))
114 me.check_hashbuffer_hashn(4, True, makefn, lambda h, n: h.hashu32b(n))
115 me.check_hashbuffer_hashn(4, False, makefn, lambda h, n: h.hashu32l(n))
116 if hasattr(makefn(0)[0], "hashu64"):
117 me.check_hashbuffer_hashn(8, True, makefn, lambda h, n: h.hashu64(n))
118 me.check_hashbuffer_hashn(8, True, makefn, lambda h, n: h.hashu64b(n))
119 me.check_hashbuffer_hashn(8, False, makefn, lambda h, n: h.hashu64l(n))
120
121 ## Check `hashbufN'.
122 me.check_hashbuffer_bufn(1, True, makefn, lambda h, x: h.hashbuf8(x))
123 me.check_hashbuffer_bufn(2, True, makefn, lambda h, x: h.hashbuf16(x))
124 me.check_hashbuffer_bufn(2, True, makefn, lambda h, x: h.hashbuf16b(x))
125 me.check_hashbuffer_bufn(2, False, makefn, lambda h, x: h.hashbuf16l(x))
126 if hasattr(makefn(0)[0], "hashbuf24"):
127 me.check_hashbuffer_bufn(3, True, makefn, lambda h, x: h.hashbuf24(x))
128 me.check_hashbuffer_bufn(3, True, makefn, lambda h, x: h.hashbuf24b(x))
129 me.check_hashbuffer_bufn(3, False, makefn, lambda h, x: h.hashbuf24l(x))
130 me.check_hashbuffer_bufn(4, True, makefn, lambda h, x: h.hashbuf32(x))
131 me.check_hashbuffer_bufn(4, True, makefn, lambda h, x: h.hashbuf32b(x))
132 me.check_hashbuffer_bufn(4, False, makefn, lambda h, x: h.hashbuf32l(x))
133 if hasattr(makefn(0)[0], "hashbuf64"):
134 me.check_hashbuffer_bufn(8, True, makefn, lambda h, x: h.hashbuf64(x))
135 me.check_hashbuffer_bufn(8, True, makefn, lambda h, x: h.hashbuf64b(x))
136 me.check_hashbuffer_bufn(8, False, makefn, lambda h, x: h.hashbuf64l(x))
137
138###--------------------------------------------------------------------------
139class TestKeysize (U.TestCase):
140
141 def test_any(me):
142
143 ## A typical one-byte spec.
144 ksz = C.seal.keysz
145 me.assertEqual(type(ksz), C.KeySZAny)
146 me.assertEqual(ksz.default, 20)
147 me.assertEqual(ksz.min, 0)
148 me.assertEqual(ksz.max, 0)
149 for n in [0, 12, 20, 5000]:
150 me.assertTrue(ksz.check(n))
151 me.assertEqual(ksz.best(n), n)
606677f6 152 me.assertEqual(ksz.pad(n), n)
553d59fe
MW
153
154 ## A typical two-byte spec. (No published algorithms actually /need/ a
155 ## two-byte key-size spec, but all of the HMAC variants use one anyway.)
156 ksz = C.sha256_hmac.keysz
157 me.assertEqual(type(ksz), C.KeySZAny)
158 me.assertEqual(ksz.default, 32)
159 me.assertEqual(ksz.min, 0)
160 me.assertEqual(ksz.max, 0)
161 for n in [0, 12, 20, 5000]:
162 me.assertTrue(ksz.check(n))
163 me.assertEqual(ksz.best(n), n)
606677f6 164 me.assertEqual(ksz.pad(n), n)
553d59fe
MW
165
166 ## Check construction.
167 ksz = C.KeySZAny(15)
168 me.assertEqual(ksz.default, 15)
169 me.assertEqual(ksz.min, 0)
170 me.assertEqual(ksz.max, 0)
171 me.assertRaises(ValueError, lambda: C.KeySZAny(-8))
172 me.assertEqual(C.KeySZAny(0).default, 0)
173
174 def test_set(me):
175 ## Note that no published algorithm uses a 16-bit `set' spec.
176
177 ## A typical spec.
178 ksz = C.salsa20.keysz
179 me.assertEqual(type(ksz), C.KeySZSet)
180 me.assertEqual(ksz.default, 32)
181 me.assertEqual(ksz.min, 10)
182 me.assertEqual(ksz.max, 32)
183 me.assertEqual(set(ksz.set), set([10, 16, 32]))
184 for x, best, pad in [(9, None, 10), (10, 10, 10), (11, 10, 16),
185 (15, 10, 16), (16, 16, 16), (17, 16, 32),
186 (31, 16, 32), (32, 32, 32), (33, 32, None)]:
187 if x == best == pad: me.assertTrue(ksz.check(x))
188 else: me.assertFalse(ksz.check(x))
189 if best is None: me.assertRaises(ValueError, ksz.best, x)
190 else: me.assertEqual(ksz.best(x), best)
606677f6
MW
191 if pad is None: me.assertRaises(ValueError, ksz.pad, x)
192 else: me.assertEqual(ksz.pad(x), pad)
553d59fe
MW
193
194 ## Check construction.
195 ksz = C.KeySZSet(7)
196 me.assertEqual(ksz.default, 7)
197 me.assertEqual(set(ksz.set), set([7]))
198 me.assertEqual(ksz.min, 7)
199 me.assertEqual(ksz.max, 7)
200 ksz = C.KeySZSet(7, [3, 6, 9])
201 me.assertEqual(ksz.default, 7)
202 me.assertEqual(set(ksz.set), set([3, 6, 7, 9]))
203 me.assertEqual(ksz.min, 3)
204 me.assertEqual(ksz.max, 9)
205
206 def test_range(me):
207 ## Note that no published algorithm uses a 16-bit `range' spec, or an
208 ## unbounded `range'.
209
210 ## A typical spec.
211 ksz = C.rijndael.keysz
212 me.assertEqual(type(ksz), C.KeySZRange)
213 me.assertEqual(ksz.default, 32)
214 me.assertEqual(ksz.min, 4)
215 me.assertEqual(ksz.max, 32)
216 me.assertEqual(ksz.mod, 4)
606677f6
MW
217 for x, best, pad in [(3, None, 4), (4, 4, 4), (5, 4, 8),
218 (15, 12, 16), (16, 16, 16), (17, 16, 20),
219 (31, 28, 32), (32, 32, 32), (33, 32, None)]:
220 if x == best == pad: me.assertTrue(ksz.check(x))
553d59fe
MW
221 else: me.assertFalse(ksz.check(x))
222 if best is None: me.assertRaises(ValueError, ksz.best, x)
223 else: me.assertEqual(ksz.best(x), best)
606677f6
MW
224 if pad is None: me.assertRaises(ValueError, ksz.pad, x)
225 else: me.assertEqual(ksz.pad(x), pad)
553d59fe
MW
226
227 ## Check construction.
228 ksz = C.KeySZRange(28, 21, 35, 7)
229 me.assertEqual(ksz.default, 28)
230 me.assertEqual(ksz.min, 21)
231 me.assertEqual(ksz.max, 35)
232 me.assertEqual(ksz.mod, 7)
233 me.assertRaises(ValueError, C.KeySZRange, 29, 21, 35, 7)
234 me.assertRaises(ValueError, C.KeySZRange, 28, 20, 35, 7)
235 me.assertRaises(ValueError, C.KeySZRange, 28, 21, 34, 7)
236 me.assertRaises(ValueError, C.KeySZRange, 28, -7, 35, 7)
237 me.assertRaises(ValueError, C.KeySZRange, 28, 35, 21, 7)
238 me.assertRaises(ValueError, C.KeySZRange, 35, 21, 28, 7)
239 me.assertRaises(ValueError, C.KeySZRange, 21, 28, 35, 7)
240
241 def test_conversions(me):
242 me.assertEqual(C.KeySZ.fromec(256), 128)
243 me.assertEqual(C.KeySZ.fromschnorr(256), 128)
244 me.assertEqual(round(C.KeySZ.fromdl(2958.6875)), 128)
245 me.assertEqual(round(C.KeySZ.fromif(2958.6875)), 128)
246 me.assertEqual(C.KeySZ.toec(128), 256)
247 me.assertEqual(C.KeySZ.toschnorr(128), 256)
248 me.assertEqual(C.KeySZ.todl(128), 2958.6875)
249 me.assertEqual(C.KeySZ.toif(128), 2958.6875)
250
251###--------------------------------------------------------------------------
252class TestCipher (T.GenericTestMixin):
253 """Test basic symmetric ciphers."""
254
255 def _test_cipher(me, ccls):
256
257 ## Check the class properties.
258 me.assertEqual(type(ccls.name), str)
259 me.assertTrue(isinstance(ccls.keysz, C.KeySZ))
260 me.assertEqual(type(ccls.blksz), int)
261
262 ## Check round-tripping.
263 k = T.span(ccls.keysz.default)
264 iv = T.span(ccls.blksz)
265 m = T.span(253)
266 enc = ccls(k)
267 dec = ccls(k)
268 try: enc.setiv(iv)
269 except ValueError: can_setiv = False
270 else:
271 can_setiv = True
272 dec.setiv(iv)
273 c0 = enc.encrypt(m[0:57])
274 m0 = dec.decrypt(c0)
275 c1 = enc.encrypt(m[57:189])
276 m1 = dec.decrypt(c1)
277 try: enc.bdry()
278 except ValueError: can_bdry = False
279 else:
280 dec.bdry()
281 can_bdry = True
282 c2 = enc.encrypt(m[189:253])
283 m2 = dec.decrypt(c2)
284 me.assertEqual(len(c0) + len(c1) + len(c2), len(m))
285 me.assertEqual(m0, m[0:57])
286 me.assertEqual(m1, m[57:189])
287 me.assertEqual(m2, m[189:253])
288
289 ## Check the `enczero' and `deczero' methods.
290 c3 = enc.enczero(32)
291 me.assertEqual(dec.decrypt(c3), C.ByteString.zero(32))
292 m4 = dec.deczero(32)
293 me.assertEqual(enc.encrypt(m4), C.ByteString.zero(32))
294
295 ## Check that ciphers which support a `boundary' operation actually
296 ## need it.
297 if can_bdry:
298 dec = ccls(k)
299 if can_setiv: dec.setiv(iv)
300 m01 = dec.decrypt(c0 + c1)
301 me.assertEqual(m01, m[0:189])
302
303 ## Check that the boundary actually does something.
304 if can_bdry:
305 dec = ccls(k)
306 if can_setiv: dec.setiv(iv)
307 m012 = dec.decrypt(c0 + c1 + c2)
308 me.assertNotEqual(m012, m)
309
310 ## Check that bad key lengths are rejected.
311 badlen = bad_key_size(ccls.keysz)
312 if badlen is not None: me.assertRaises(ValueError, ccls, T.span(badlen))
313
314TestCipher.generate_testcases((name, C.gcciphers[name]) for name in
315 ["des-ecb", "rijndael-cbc", "twofish-cfb", "serpent-ofb",
316 "blowfish-counter", "rc4", "seal", "salsa20/8", "shake128-xof"])
317
318###--------------------------------------------------------------------------
319class BaseTestHash (HashBufferTestMixin):
320 """Base class for testing hash functions."""
321
322 def check_hash(me, hcls, need_bufsz = True):
323 """
324 Check hash class HCLS.
325
326 If NEED_BUFSZ is false, then don't insist that HCLS have working `bufsz',
327 `name', or `hashsz' attributes. This test is mostly reused for MACs,
328 which don't have these attributes.
329 """
330 ## Check the class properties.
331 if need_bufsz:
332 me.assertEqual(type(hcls.name), str)
333 me.assertEqual(type(hcls.bufsz), int)
334 me.assertEqual(type(hcls.hashsz), int)
335
336 ## Set some initial values.
337 m = T.span(131)
338 h = hcls().hash(m).done()
339
340 ## Check that hash length comes out right.
341 if need_bufsz: me.assertEqual(len(h), hcls.hashsz)
342
343 ## Check that we get the same answer if we split the message up.
344 me.assertEqual(h, hcls().hash(m[0:73]).hash(m[73:131]).done())
345
346 ## Check the `check' method.
347 me.assertTrue(hcls().hash(m).check(h))
348 me.assertFalse(hcls().hash(m).check(h ^ len(h)*C.bytes("aa")))
349
350 ## Check the menagerie of random hashing methods.
351 def mkhash(_):
352 h = hcls()
353 return h, h.done
354 me.check_hashbuffer(mkhash)
355
356class TestHash (BaseTestHash, T.GenericTestMixin):
357 """Test hash functions."""
358 def _test_hash(me, hcls): me.check_hash(hcls, need_bufsz = True)
359
360TestHash.generate_testcases((name, C.gchashes[name]) for name in
361 ["md5", "sha", "whirlpool", "sha256", "sha512/224", "sha3-384", "shake256",
362 "crc32"])
363
364###--------------------------------------------------------------------------
365class TestMessageAuthentication (BaseTestHash, T.GenericTestMixin):
366 """Test message authentication codes."""
367
368 def _test_mac(me, mcls):
369
370 ## Check the MAC properties.
371 me.assertEqual(type(mcls.name), str)
372 me.assertTrue(isinstance(mcls.keysz, C.KeySZ))
373 me.assertEqual(type(mcls.tagsz), int)
374
375 ## Test hashing.
376 k = T.span(mcls.keysz.default)
377 key = mcls(k)
378 me.check_hash(key, need_bufsz = False)
379
380 ## Check that bad key lengths are rejected.
381 badlen = bad_key_size(mcls.keysz)
382 if badlen is not None: me.assertRaises(ValueError, mcls, T.span(badlen))
383
384TestMessageAuthentication.generate_testcases \
385 ((name, C.gcmacs[name]) for name in
386 ["sha-hmac", "rijndael-cmac", "twofish-pmac1", "kmac128"])
387
388class TestPoly1305 (HashBufferTestMixin):
389 """Check the Poly1305 one-time message authentication function."""
390
391 def test_poly1305(me):
392
393 ## Check the MAC properties.
394 me.assertEqual(C.poly1305.name, "poly1305")
395 me.assertEqual(type(C.poly1305.keysz), C.KeySZSet)
396 me.assertEqual(C.poly1305.keysz.default, 16)
397 me.assertEqual(set(C.poly1305.keysz.set), set([16]))
398 me.assertEqual(C.poly1305.tagsz, 16)
399 me.assertEqual(C.poly1305.masksz, 16)
400
401 ## Set some initial values.
402 k = T.span(16)
403 u = T.span(64)[-16:]
404 m = T.span(149)
405 key = C.poly1305(k)
406 t = key(u).hash(m).done()
407
408 ## Check the key properties.
409 me.assertEqual(len(t), 16)
410
411 ## Check that we get the same answer if we split the message up.
412 me.assertEqual(t, key(u).hash(m[0:86]).hash(m[86:149]).done())
413
414 ## Check the `check' method.
415 me.assertTrue(key(u).hash(m).check(t))
416 me.assertFalse(key(u).hash(m).check(t ^ 16*C.bytes("cc")))
417
418 ## Check the menagerie of random hashing methods.
419 def mkhash(_):
420 h = key(u)
421 return h, h.done
422 me.check_hashbuffer(mkhash)
423
424 ## Check that we can't complete hashing without a mask.
425 me.assertRaises(ValueError, key().hash(m).done)
426
427 ## Check `concat'.
428 h0 = key().hash(m[0:96])
429 h1 = key().hash(m[96:117])
430 me.assertEqual(t, key(u).concat(h0, h1).hash(m[117:149]).done())
431 key1 = C.poly1305(k)
432 me.assertRaises(TypeError, key().concat, key1().hash(m[0:96]), h1)
433 me.assertRaises(TypeError, key().concat, h0, key1().hash(m[96:117]))
434 me.assertRaises(ValueError, key().concat, key().hash(m[0:93]), h1)
435
436###--------------------------------------------------------------------------
437class TestHLatin (U.TestCase):
438 """Test the `hsalsa20' and `hchacha20' functions."""
439
440 def test_hlatin(me):
441 kk = [T.span(sz) for sz in [32]]
442 n = T.span(16)
443 bad_k = T.span(18)
444 bad_n = T.span(13)
445 for fn in [C.hsalsa208_prf, C.hsalsa2012_prf, C.hsalsa20_prf,
446 C.hchacha8_prf, C.hchacha12_prf, C.hchacha20_prf]:
447 for k in kk:
448 h = fn(k, n)
449 me.assertEqual(len(h), 32)
450 me.assertRaises(ValueError, fn, bad_k, n)
451 me.assertRaises(ValueError, fn, k, bad_n)
452
453###--------------------------------------------------------------------------
454class TestKeccak (HashBufferTestMixin):
455 """Test the Keccak-p[1600, n] sponge function."""
456
457 def test_keccak(me):
458
459 ## Make a state and feed some stuff into it.
460 m0 = T.bin("some initial string")
461 m1 = T.bin("awesome follow-up string")
462 st0 = C.Keccak1600()
463 me.assertEqual(st0.nround, 24)
464 st0.mix(m0).step()
465
466 ## Make another step with a different round count.
467 st1 = C.Keccak1600(23)
468 st1.mix(m0).step()
469 me.assertNotEqual(st0.extract(32), st1.extract(32))
470
471 ## Check error conditions.
472 _ = st0.extract(200)
473 me.assertRaises(ValueError, st0.extract, 201)
474 st0.mix(T.span(200))
475 me.assertRaises(ValueError, st0.mix, T.span(201))
476
477 def check_shake(me, xcls, c, done_matches_xof = True):
478 """
479 Test the SHAKE and cSHAKE XOFs.
480
481 This is also used for testing KMAC, but that sets DONE_MATCHES_XOF false
482 to indicate that the XOF output is range-separated from the fixed-length
483 outputs (unlike the basic SHAKE functions).
484 """
485
486 ## Check the hash attributes.
487 x = xcls()
488 me.assertEqual(x.rate, 200 - c)
489 me.assertEqual(x.buffered, 0)
490 me.assertEqual(x.state, "absorb")
491
492 ## Set some initial values.
493 func = T.bin("TESTXOF")
494 perso = T.bin("catacomb-python test")
495 m = T.span(167)
496 h0 = xcls().hash(m).done(193)
497 me.assertEqual(len(h0), 193)
498 h1 = xcls(func = func, perso = perso).hash(m).done(193)
499 me.assertEqual(len(h1), 193)
500 me.assertNotEqual(h0, h1)
501
502 ## Check input and output in pieces, and the state machine.
503 if done_matches_xof: h = h0
504 else: h = xcls().hash(m).xof().get(len(h0))
505 x = xcls().hash(m[0:76]).hash(m[76:167]).xof()
506 me.assertEqual(h, x.get(98) + x.get(95))
507
508 ## Check masking.
509 x = xcls().hash(m).xof()
510 me.assertEqual(x.mask(m), C.ByteString(m) ^ C.ByteString(h[0:len(m)]))
511
512 ## Check the `check' method.
513 me.assertTrue(xcls().hash(m).check(h0))
514 me.assertFalse(xcls().hash(m).check(h1))
515
516 ## Check the menagerie of random hashing methods.
517 def mkhash(_):
518 x = xcls(func = func, perso = perso)
519 return x, lambda: x.done(100 - x.rate//2)
520 me.check_hashbuffer(mkhash)
521
522 ## Check the state machine tracking.
523 x = xcls(); me.assertEqual(x.state, "absorb")
524 x.hash(m); me.assertEqual(x.state, "absorb")
525 xx = x.copy()
526 h = xx.done(100 - x.rate//2)
527 me.assertEqual(xx.state, "dead")
528 me.assertRaises(ValueError, xx.done, 1)
529 me.assertRaises(ValueError, xx.get, 1)
530 me.assertEqual(x.state, "absorb")
531 me.assertRaises(ValueError, x.get, 1)
532 x.xof(); me.assertEqual(x.state, "squeeze")
533 me.assertRaises(ValueError, x.done, 1)
534 _ = x.get(1)
535 yy = x.copy(); me.assertEqual(yy.state, "squeeze")
536
537 def test_shake128(me): me.check_shake(C.Shake128, 32)
538 def test_shake256(me): me.check_shake(C.Shake256, 64)
539
540 def check_kmac(me, mcls, c):
541 k = T.span(32)
542 me.check_shake(lambda func = None, perso = T.bin(""):
543 mcls(k, perso = perso),
544 c, done_matches_xof = False)
545
546 def test_kmac128(me): me.check_kmac(C.KMAC128, 32)
547 def test_kmac256(me): me.check_kmac(C.KMAC256, 64)
548
549###--------------------------------------------------------------------------
550class TestPRP (T.GenericTestMixin):
551 """Test pseudorandom permutations (PRPs)."""
552
553 def _test_prp(me, pcls):
554
555 ## Check the PRP properties.
556 me.assertEqual(type(pcls.name), str)
557 me.assertTrue(isinstance(pcls.keysz, C.KeySZ))
558 me.assertEqual(type(pcls.blksz), int)
559
560 ## Check round-tripping.
561 k = T.span(pcls.keysz.default)
562 key = pcls(k)
563 m = T.span(pcls.blksz)
564 c = key.encrypt(m)
565 me.assertEqual(len(c), pcls.blksz)
566 me.assertEqual(m, key.decrypt(c))
567
568 ## Check that bad key lengths are rejected.
569 badlen = bad_key_size(pcls.keysz)
570 if badlen is not None: me.assertRaises(ValueError, pcls, T.span(badlen))
571
572 ## Check that bad blocks are rejected.
573 badblk = T.span(pcls.blksz + 1)
574 me.assertRaises(ValueError, key.encrypt, badblk)
575 me.assertRaises(ValueError, key.decrypt, badblk)
576
577TestPRP.generate_testcases((name, C.gcprps[name]) for name in
578 ["desx", "blowfish", "rijndael"])
579
580###----- That's all, folks --------------------------------------------------
581
582if __name__ == "__main__": U.main()