Merge branch '2.4.x' into 2.5.x
authorMark Wooding <mdw@distorted.org.uk>
Sat, 9 May 2020 19:39:18 +0000 (20:39 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 9 May 2020 19:39:18 +0000 (20:39 +0100)
* 2.4.x:
  Release 2.4.5.
  math/group-parse.c (group-parse): Parse binary-group descriptions.
  math/group-parse.c: Fix copyright notice.
  *.c: Check for ARM64 SIMD before using the accelerated code.
  base/dispatch.c: Recognize `CPUFEAT_ARM_NEON' as requesting ARM64 SIMD.
  symm/t/chacha: Missing test from RFC8439.
  math/t/{mpx,mpmont}: Add some extra tests for flushing out `mul4' bugs.
  math/mpx-mul4-*: Test the `...zc' variants too.
  math/Makefile.am, symm/Makefile.am: Use `--no-install' on oddball tests.
  progs/pixie.c: Don't crash when trying to set an empty passphrase.
  configure.ac, vars.am: Use host-specific link options for test programs.

271 files changed:
.gitignore
base/Makefile.am
base/asm-common.h
base/dispatch.c
base/dispatch.h
base/keysz.c
base/keysz.h
base/regdump-arm.S [new file with mode: 0644]
base/regdump-arm64.S [new file with mode: 0644]
base/regdump-x86ish.S [new file with mode: 0644]
base/regdump.c [new file with mode: 0644]
base/regdump.h [new file with mode: 0644]
base/rsvr.c [new file with mode: 0644]
base/rsvr.h [new file with mode: 0644]
base/t/rsvr [new file with mode: 0644]
base/test-regdump-a64.S [new file with mode: 0644]
base/test-regdump-arm.S [new file with mode: 0644]
base/test-regdump-x86ish.S [new file with mode: 0644]
configure.ac
debian/catacomb2.symbols
debian/changelog
debian/control
math/Makefile.am
math/f25519.c
math/fgoldi.c
math/mp-sqrt.c
math/mpmont.c
math/mpx-mul4-amd64-sse2.S
math/mpx-mul4-x86-sse2.S
math/mpx.c
math/pgen-granfrob.c [new file with mode: 0644]
math/pgen.c
math/pgen.h
math/t/pgen
progs/.gitignore [new file with mode: 0644]
progs/Makefile.am
progs/catcrypt.1
progs/catcrypt.c
progs/cc-kem.c
progs/perftest.c
pub/dh-param.c
symm/.gitignore
symm/Makefile.am
symm/blkc.h
symm/cbc-def.h
symm/cbc.h
symm/ccm-def.h [new file with mode: 0644]
symm/ccm.c [new file with mode: 0644]
symm/ccm.h [new file with mode: 0644]
symm/cfb-def.h
symm/cfb.h
symm/chacha-arm-neon.S
symm/chacha-arm64.S
symm/chacha-poly1305.c [new file with mode: 0644]
symm/chacha-x86ish-sse2.S
symm/chacha.c
symm/chacha.h
symm/cmac-def.h [new file with mode: 0644]
symm/cmac.h [new file with mode: 0644]
symm/counter-def.h
symm/counter.h
symm/daftstory.h [deleted file]
symm/eax-def.h [new file with mode: 0644]
symm/eax.h [new file with mode: 0644]
symm/ecb-def.h
symm/gaead.c [new file with mode: 0644]
symm/gaead.h [new file with mode: 0644]
symm/gcm-arm-crypto.S [new file with mode: 0644]
symm/gcm-arm64-pmull.S [new file with mode: 0644]
symm/gcm-def.h [new file with mode: 0644]
symm/gcm-x86ish-pclmul.S [new file with mode: 0644]
symm/gcm.c [new file with mode: 0644]
symm/gcm.h [new file with mode: 0644]
symm/hash.h
symm/hmac-def.h
symm/keccak1600.c
symm/latinpoly-def.h [new file with mode: 0644]
symm/latinpoly-test.c [new file with mode: 0644]
symm/latinpoly-test.h [new file with mode: 0644]
symm/latinpoly.c [new file with mode: 0644]
symm/latinpoly.h [new file with mode: 0644]
symm/mgf-def.h
symm/mgf.h
symm/modes-test.c [new file with mode: 0644]
symm/modes-test.h [new file with mode: 0644]
symm/modes.am.in
symm/ocb.c [new file with mode: 0644]
symm/ocb.h [new file with mode: 0644]
symm/ocb1-def.h [new file with mode: 0644]
symm/ocb1.h [new file with mode: 0644]
symm/ocb3-def.h [new file with mode: 0644]
symm/ocb3.h [new file with mode: 0644]
symm/ofb-def.h
symm/ofb.h
symm/pmac1-def.h [new file with mode: 0644]
symm/pmac1.h [new file with mode: 0644]
symm/poly1305.c
symm/rijndael-arm-crypto.S
symm/rijndael-arm64-crypto.S
symm/rijndael-base.c
symm/rijndael-x86ish-aesni.S
symm/rijndael.c
symm/salsa20-arm-neon.S
symm/salsa20-arm64.S
symm/salsa20-core.h
symm/salsa20-poly1305.c [new file with mode: 0644]
symm/salsa20-x86ish-sse2.S
symm/salsa20.c
symm/salsa20.h
symm/seal.c
symm/seal.h
symm/stub.h.in
symm/t/blowfish
symm/t/cast128
symm/t/cast256.local [new file with mode: 0644]
symm/t/chacha
symm/t/des
symm/t/des3
symm/t/desx
symm/t/gcm [new file with mode: 0644]
symm/t/idea
symm/t/mars.local [new file with mode: 0644]
symm/t/modes/blowfish-cbc.regress [new file with mode: 0644]
symm/t/modes/blowfish-cfb.regress [new file with mode: 0644]
symm/t/modes/blowfish-counter.regress [new file with mode: 0644]
symm/t/modes/blowfish-ecb.regress [new file with mode: 0644]
symm/t/modes/blowfish-ofb.regress [new file with mode: 0644]
symm/t/modes/cast128-cbc.regress [new file with mode: 0644]
symm/t/modes/cast128-cfb.regress [new file with mode: 0644]
symm/t/modes/cast128-counter.regress [new file with mode: 0644]
symm/t/modes/cast128-ecb.regress [new file with mode: 0644]
symm/t/modes/cast128-ofb.regress [new file with mode: 0644]
symm/t/modes/cast256-cbc.regress [new file with mode: 0644]
symm/t/modes/cast256-cfb.regress [new file with mode: 0644]
symm/t/modes/cast256-counter.regress [new file with mode: 0644]
symm/t/modes/cast256-ecb.regress [new file with mode: 0644]
symm/t/modes/cast256-ofb.regress [new file with mode: 0644]
symm/t/modes/des-cbc.regress [new file with mode: 0644]
symm/t/modes/des-cfb.regress [new file with mode: 0644]
symm/t/modes/des-counter.regress [new file with mode: 0644]
symm/t/modes/des-ecb.regress [new file with mode: 0644]
symm/t/modes/des-ofb.regress [new file with mode: 0644]
symm/t/modes/des3-cbc.regress [new file with mode: 0644]
symm/t/modes/des3-cfb.regress [new file with mode: 0644]
symm/t/modes/des3-counter.regress [new file with mode: 0644]
symm/t/modes/des3-ecb.regress [new file with mode: 0644]
symm/t/modes/des3-ofb.regress [new file with mode: 0644]
symm/t/modes/desx-cbc.regress [new file with mode: 0644]
symm/t/modes/desx-cfb.regress [new file with mode: 0644]
symm/t/modes/desx-counter.regress [new file with mode: 0644]
symm/t/modes/desx-ecb.regress [new file with mode: 0644]
symm/t/modes/desx-ofb.regress [new file with mode: 0644]
symm/t/modes/has160-mgf.regress [new file with mode: 0644]
symm/t/modes/idea-cbc.regress [new file with mode: 0644]
symm/t/modes/idea-cfb.regress [new file with mode: 0644]
symm/t/modes/idea-counter.regress [new file with mode: 0644]
symm/t/modes/idea-ecb.regress [new file with mode: 0644]
symm/t/modes/idea-ofb.regress [new file with mode: 0644]
symm/t/modes/mars-cbc.regress [new file with mode: 0644]
symm/t/modes/mars-cfb.regress [new file with mode: 0644]
symm/t/modes/mars-counter.regress [new file with mode: 0644]
symm/t/modes/mars-ecb.regress [new file with mode: 0644]
symm/t/modes/mars-ofb.regress [new file with mode: 0644]
symm/t/modes/md2-mgf.regress [new file with mode: 0644]
symm/t/modes/md4-mgf.regress [new file with mode: 0644]
symm/t/modes/md5-mgf.regress [new file with mode: 0644]
symm/t/modes/noekeon-cbc.regress [new file with mode: 0644]
symm/t/modes/noekeon-cfb.regress [new file with mode: 0644]
symm/t/modes/noekeon-counter.regress [new file with mode: 0644]
symm/t/modes/noekeon-ecb.regress [new file with mode: 0644]
symm/t/modes/noekeon-ofb.regress [new file with mode: 0644]
symm/t/modes/rc2-cbc.regress [new file with mode: 0644]
symm/t/modes/rc2-cfb.regress [new file with mode: 0644]
symm/t/modes/rc2-counter.regress [new file with mode: 0644]
symm/t/modes/rc2-ecb.regress [new file with mode: 0644]
symm/t/modes/rc2-ofb.regress [new file with mode: 0644]
symm/t/modes/rc5-cbc.regress [new file with mode: 0644]
symm/t/modes/rc5-cfb.regress [new file with mode: 0644]
symm/t/modes/rc5-counter.regress [new file with mode: 0644]
symm/t/modes/rc5-ecb.regress [new file with mode: 0644]
symm/t/modes/rc5-ofb.regress [new file with mode: 0644]
symm/t/modes/rijndael-cbc.regress [new file with mode: 0644]
symm/t/modes/rijndael-cfb.regress [new file with mode: 0644]
symm/t/modes/rijndael-counter.regress [new file with mode: 0644]
symm/t/modes/rijndael-ecb.regress [new file with mode: 0644]
symm/t/modes/rijndael-ofb.regress [new file with mode: 0644]
symm/t/modes/rijndael192-cbc.regress [new file with mode: 0644]
symm/t/modes/rijndael192-cfb.regress [new file with mode: 0644]
symm/t/modes/rijndael192-counter.regress [new file with mode: 0644]
symm/t/modes/rijndael192-ecb.regress [new file with mode: 0644]
symm/t/modes/rijndael192-ofb.regress [new file with mode: 0644]
symm/t/modes/rijndael256-cbc.regress [new file with mode: 0644]
symm/t/modes/rijndael256-cfb.regress [new file with mode: 0644]
symm/t/modes/rijndael256-counter.regress [new file with mode: 0644]
symm/t/modes/rijndael256-ecb.regress [new file with mode: 0644]
symm/t/modes/rijndael256-ofb.regress [new file with mode: 0644]
symm/t/modes/rmd128-mgf.regress [new file with mode: 0644]
symm/t/modes/rmd160-mgf.regress [new file with mode: 0644]
symm/t/modes/rmd256-mgf.regress [new file with mode: 0644]
symm/t/modes/rmd320-mgf.regress [new file with mode: 0644]
symm/t/modes/safer-cbc.regress [new file with mode: 0644]
symm/t/modes/safer-cfb.regress [new file with mode: 0644]
symm/t/modes/safer-counter.regress [new file with mode: 0644]
symm/t/modes/safer-ecb.regress [new file with mode: 0644]
symm/t/modes/safer-ofb.regress [new file with mode: 0644]
symm/t/modes/safersk-cbc.regress [new file with mode: 0644]
symm/t/modes/safersk-cfb.regress [new file with mode: 0644]
symm/t/modes/safersk-counter.regress [new file with mode: 0644]
symm/t/modes/safersk-ecb.regress [new file with mode: 0644]
symm/t/modes/safersk-ofb.regress [new file with mode: 0644]
symm/t/modes/serpent-cbc.regress [new file with mode: 0644]
symm/t/modes/serpent-cfb.regress [new file with mode: 0644]
symm/t/modes/serpent-counter.regress [new file with mode: 0644]
symm/t/modes/serpent-ecb.regress [new file with mode: 0644]
symm/t/modes/serpent-ofb.regress [new file with mode: 0644]
symm/t/modes/sha-mgf.regress [new file with mode: 0644]
symm/t/modes/sha224-mgf.regress [new file with mode: 0644]
symm/t/modes/sha256-mgf.regress [new file with mode: 0644]
symm/t/modes/sha3-224-mgf.regress [new file with mode: 0644]
symm/t/modes/sha3-256-mgf.regress [new file with mode: 0644]
symm/t/modes/sha3-384-mgf.regress [new file with mode: 0644]
symm/t/modes/sha3-512-mgf.regress [new file with mode: 0644]
symm/t/modes/sha384-mgf.regress [new file with mode: 0644]
symm/t/modes/sha512-224-mgf.regress [new file with mode: 0644]
symm/t/modes/sha512-256-mgf.regress [new file with mode: 0644]
symm/t/modes/sha512-mgf.regress [new file with mode: 0644]
symm/t/modes/skipjack-cbc.regress [new file with mode: 0644]
symm/t/modes/skipjack-cfb.regress [new file with mode: 0644]
symm/t/modes/skipjack-counter.regress [new file with mode: 0644]
symm/t/modes/skipjack-ecb.regress [new file with mode: 0644]
symm/t/modes/skipjack-ofb.regress [new file with mode: 0644]
symm/t/modes/square-cbc.regress [new file with mode: 0644]
symm/t/modes/square-cfb.regress [new file with mode: 0644]
symm/t/modes/square-counter.regress [new file with mode: 0644]
symm/t/modes/square-ecb.regress [new file with mode: 0644]
symm/t/modes/square-ofb.regress [new file with mode: 0644]
symm/t/modes/tea-cbc.regress [new file with mode: 0644]
symm/t/modes/tea-cfb.regress [new file with mode: 0644]
symm/t/modes/tea-counter.regress [new file with mode: 0644]
symm/t/modes/tea-ecb.regress [new file with mode: 0644]
symm/t/modes/tea-ofb.regress [new file with mode: 0644]
symm/t/modes/tiger-mgf.regress [new file with mode: 0644]
symm/t/modes/twofish-cbc.regress [new file with mode: 0644]
symm/t/modes/twofish-cfb.regress [new file with mode: 0644]
symm/t/modes/twofish-counter.regress [new file with mode: 0644]
symm/t/modes/twofish-ecb.regress [new file with mode: 0644]
symm/t/modes/twofish-ofb.regress [new file with mode: 0644]
symm/t/modes/whirlpool-mgf.regress [new file with mode: 0644]
symm/t/modes/whirlpool256-mgf.regress [new file with mode: 0644]
symm/t/modes/xtea-cbc.regress [new file with mode: 0644]
symm/t/modes/xtea-cfb.regress [new file with mode: 0644]
symm/t/modes/xtea-counter.regress [new file with mode: 0644]
symm/t/modes/xtea-ecb.regress [new file with mode: 0644]
symm/t/modes/xtea-ofb.regress [new file with mode: 0644]
symm/t/noekeon
symm/t/rc2
symm/t/rc5
symm/t/rijndael.local [new file with mode: 0644]
symm/t/rijndael192
symm/t/rijndael256
symm/t/safer
symm/t/safersk
symm/t/salsa20.local
symm/t/serpent.local [new file with mode: 0644]
symm/t/skipjack
symm/t/square
symm/t/tea
symm/t/twofish.local [new file with mode: 0644]
symm/t/xtea
utils/advmodes [new file with mode: 0755]
utils/gcm-ref [new file with mode: 0755]

index 1d7acb5..9c2b37d 100644 (file)
@@ -1,61 +1,10 @@
 Makefile.in
-aclocal.m4
-configure
-COPYING.LIB
-autom4te.cache
-config
-precomp
-progs/getdate.h
-progs/getdate.y
-symm/modes.am
-symm/stubs.am
+/aclocal.m4
+/configure
+/COPYING.LIB
+/autom4te.cache/
+/config/
+/precomp/
 *.sage.py
 *.t
 *.to
-/symm/safersk.h
-/symm/salsa2012.h
-/symm/salsa208.h
-/symm/salsa20-ietf.h
-/symm/salsa2012-ietf.h
-/symm/salsa208-ietf.h
-/symm/sha224.h
-/symm/sha384.h
-/symm/whirlpool256.h
-/symm/xsalsa20.h
-/symm/xsalsa2012.h
-/symm/xsalsa208.h
-/symm/stubs.gen-stamp
-/symm/t/salsa20
-/symm/xchacha12.h
-/symm/xchacha20.h
-/symm/xchacha8.h
-/symm/chacha12.h
-/symm/chacha20.h
-/symm/chacha8.h
-/symm/chacha12-ietf.h
-/symm/chacha20-ietf.h
-/symm/chacha8-ietf.h
-/symm/xchacha.h
-/symm/kmac128.h
-/symm/kmac256.h
-/symm/safersk.c
-/symm/sha224.c
-/symm/sha3-224.c
-/symm/sha3-224.h
-/symm/sha3-256.c
-/symm/sha3-256.h
-/symm/sha3-384.c
-/symm/sha3-384.h
-/symm/sha3-512.c
-/symm/sha3-512.h
-/symm/sha384.c
-/symm/sha512-224.c
-/symm/sha512-224.h
-/symm/sha512-256.c
-/symm/sha512-256.h
-/symm/shake128.h
-/symm/shake256.h
-/symm/t/sha3
-/symm/whirlpool256.c
-/symm/shake128-xof.h
-/symm/shake256-xof.h
index c9560ca..145f9c3 100644 (file)
@@ -29,6 +29,8 @@ include $(top_srcdir)/vars.am
 noinst_LTLIBRARIES      = libbase.la
 libbase_la_SOURCES      =
 
+TEST_LIBS               = libbase.la
+
 ###--------------------------------------------------------------------------
 ### Component files.
 
@@ -55,7 +57,29 @@ libbase_la_SOURCES   += lmem.c
 ## Clearing secrets from memory.
 pkginclude_HEADERS     += paranoia.h
 
+## Reservoir handling.
+pkginclude_HEADERS     += rsvr.h
+libbase_la_SOURCES     += rsvr.c
+TESTS                  += rsvr.t$(EXEEXT)
+EXTRA_DIST             += t/rsvr
+
 ## Base definitions for assembler source.
 EXTRA_DIST             += asm-common.h
 
+if ASM_DEBUG
+libbase_la_SOURCES     += regdump.c regdump.h
+if CPUFAM_X86
+libbase_la_SOURCES     += regdump-x86ish.S
+endif
+if CPUFAM_AMD64
+libbase_la_SOURCES     += regdump-x86ish.S
+endif
+if CPUFAM_ARMEL
+libbase_la_SOURCES     += regdump-arm.S
+endif
+if CPUFAM_ARM64
+libbase_la_SOURCES     += regdump-arm64.S
+endif
+endif
+
 ###----- That's all, folks --------------------------------------------------
index 8e51ea3..44c223d 100644 (file)
@@ -24,6 +24,9 @@
 /// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 /// MA 02111-1307, USA.
 
+#ifndef CATACOMB_ASM_COMMON_H
+#define CATACOMB_ASM_COMMON_H
+
 ///--------------------------------------------------------------------------
 /// General definitions.
 
@@ -217,11 +220,11 @@ name:
 #  define INTADDR__1(addr, got) addr
 #endif
 
-// Permutations for SIMD instructions.  SHUF(D, C, B, A) is an immediate,
-// suitable for use in `pshufd' or `shufpd', which copies element D
-// (0 <= D < 4) of the source to element 3 of the destination, element C to
-// element 2, element B to element 1, and element A to element 0.
-#define SHUF(d, c, b, a) (64*(d) + 16*(c) + 4*(b) + (a))
+// Permutations for SIMD instructions.  SHUF(A, B, C, D) is an immediate,
+// suitable for use in `pshufd' or `shufpd', which copies element A
+// (0 <= A < 4) of the source to element 0 of the destination, element B to
+// element 1, element C to element 2, and element D to element 3.
+#define SHUF(a, b, c, d) ((a) + 4*(b) + 16*(c) + 64*(d))
 
 // Map register names to their individual pieces.
 
@@ -255,10 +258,10 @@ name:
 #  define _DECOR_abcd_q(reg) r##reg##x
 #endif
 
-#define _DECOR_xp_b(reg) reg##l
 #define _DECOR_xp_w(reg) reg
 #define _DECOR_xp_d(reg) e##reg
 #if CPUFAM_AMD64
+#  define _DECOR_xp_b(reg) reg##l
 #  define _DECOR_xp_q(reg) r##reg
 #endif
 
@@ -276,22 +279,33 @@ name:
 #  define _DECOR_rn_r(reg) reg
 #endif
 
+#define _DECOR_mem_b(addr) byte ptr addr
+#define _DECOR_mem_w(addr) word ptr addr
+#define _DECOR_mem_d(addr) dword ptr addr
+#if CPUFAM_AMD64
+#  define _DECOR_mem_q(addr) qword ptr addr
+#endif
+
+#define _DECOR_imm_b(imm) byte imm
+#define _DECOR_imm_w(imm) word imm
+#define _DECOR_imm_d(imm) dword imm
+#if CPUFAM_AMD64
+#  define _DECOR_imm_q(imm) qword imm
+#endif
+
 #if CPUFAM_X86
 #  define _DECOR_abcd_r(reg) e##reg##x
 #  define _DECOR_xp_r(reg) e##reg
 #  define _DECOR_ip_r(reg) e##reg
+#  define _DECOR_mem_r(addr) dword ptr addr
+#  define _DECOR_imm_r(imm) dword imm
 #endif
 #if CPUFAM_AMD64
 #  define _DECOR_abcd_r(reg) r##reg##x
 #  define _DECOR_xp_r(reg) r##reg
 #  define _DECOR_ip_r(reg) r##reg
-#endif
-
-#define _DECOR_mem_b(addr) byte ptr addr
-#define _DECOR_mem_w(addr) word ptr addr
-#define _DECOR_mem_d(addr) dword ptr addr
-#if CPUFAM_AMD64
-#  define _DECOR_mem_q(addr) qword ptr addr
+#  define _DECOR_mem_r(addr) qword ptr addr
+#  define _DECOR_imm_r(imm) qword imm
 #endif
 
 // R_r(decor) applies decoration decor to register r, which is an internal
@@ -321,6 +335,9 @@ name:
 // address addr (which should supply its own square-brackets).
 #define MEM(decor, addr) _DECOR(mem, decor, addr)
 
+// Refer to an immediate datum of the type implied by decor.
+#define IMM(decor, imm) _DECOR(mem, decor, imm)
+
 // Applies decoration decor to assembler-level register name reg.
 #define _REGFORM(reg, decor) _GLUE(_REGFORM_, reg)(decor)
 
@@ -436,7 +453,7 @@ name:
 #define WHOLE(reg) _REGFORM(reg, r)
 
 // Stack management and unwinding.
-.macro setfp   fp, offset = 0
+.macro setfp   fp=R_bp(r), offset=0
   .if \offset == 0
        mov     \fp, R_sp(r)
 #if __ELF__
@@ -459,7 +476,7 @@ name:
        .macro dropfp; _dropfp  \fp, \offset; .endm
 .endm
 
-.macro _dropfp fp, offset = 0
+.macro _dropfp fp, offset=0
   .if \offset == 0
        mov     R_sp(r), \fp
 #if __ELF__
@@ -532,117 +549,6 @@ name:
 
 #endif
 
-#if CPUFAM_X86
-
-.macro _reg.0
-       // Stash GP registers and establish temporary stack frame.
-       pushfd
-       push    eax
-       push    ecx
-       push    edx
-       push    ebp
-       mov     ebp, esp
-       and     esp, ~15
-       sub     esp, 512
-       fxsave  [esp]
-.endm
-
-.macro _reg.1
-.endm
-
-.macro _reg.2
-.endm
-
-.macro _reg.3  fmt
-       // Print FMT and the other established arguments.
-       lea     eax, .L$_reg$msg.\@
-       push    eax
-       call    printf
-       jmp     .L$_reg$cont.\@
-.L$_reg$msg.\@:
-       .ascii  ";; \fmt\n\0"
-.L$_reg$cont.\@:
-       mov     eax, ebp
-       and     eax, ~15
-       sub     eax, 512
-       fxrstor [eax]
-       mov     esp, ebp
-       pop     ebp
-       pop     edx
-       pop     ecx
-       pop     eax
-       popfd
-.endm
-
-.macro msg     msg
-       _reg.0
-       _reg.1
-       _reg.2
-       _reg.3  "\msg"
-.endm
-
-.macro reg     r, msg
-       _reg.0
-  .ifeqs "\r", "esp"
-       lea     eax, [ebp + 20]
-       push    eax
-  .else
-    .ifeqs "\r", "ebp"
-       push    [ebp]
-    .else
-       push    \r
-    .endif
-  .endif
-       _reg.1
-       _reg.2
-       _reg.3  "\msg: \r = %08x"
-.endm
-
-.macro xmmreg  r, msg
-       _reg.0
-       _reg.1
-       _reg.2
-       movdqu  xmm0, \r
-       pshufd  xmm0, xmm0, 0x1b
-       sub     esp, 16
-       movdqa  [esp], xmm0
-       _reg.3  "\msg: \r = %08x %08x %08x %08x"
-.endm
-
-.macro mmreg   r, msg
-       _reg.0
-       _reg.1
-       _reg.2
-       pshufw  \r, \r, 0x4e
-       sub     esp, 8
-       movq    [esp], \r
-       _reg.3  "\msg: \r = %08x %08x"
-.endm
-
-.macro freg    i, msg
-       _reg.0
-       _reg.1
-       _reg.2
-       finit
-       fldt    [esp + 32 + 16*\i]
-       sub     esp, 12
-       fstpt   [esp]
-       _reg.3  "\msg: st(\i) = %.20Lg"
-.endm
-
-.macro fxreg   i, msg
-       _reg.0
-       _reg.1
-       _reg.2
-       finit
-       fldt    [esp + 32 + 16*\i]
-       sub     esp, 12
-       fstpt   [esp]
-       _reg.3  "\msg: st(\i) = %La"
-.endm
-
-#endif
-
 ///--------------------------------------------------------------------------
 /// ARM-specific hacking.
 
@@ -706,12 +612,12 @@ name:
 #if WANT_PIC
        ldr\cond \reg, .L$_leaextq$\@
 .L$_leaextq_pc$\@:
-       .if     .L$_pcoff == 8
+  .if .L$_pcoff == 8
        ldr\cond \reg, [pc, \reg]
-       .else
+  .else
        add\cond \reg, pc
        ldr\cond \reg, [\reg]
-       .endif
+  .endif
   _LIT
        .balign 4
 .L$_leaextq$\@:
@@ -722,6 +628,29 @@ name:
 #endif
 .endm
 
+.macro vzero   vz=q15
+       // Set VZ (default q15) to zero.
+       vmov.u32 \vz, #0
+.endm
+
+.macro vshl128 vd, vn, nbit, vz=q15
+       // Set VD to VN shifted left by NBIT.  Assume VZ (default q15) is
+       // all-bits-zero.  NBIT must be a multiple of 8.
+  .if \nbit&3 != 0
+       .error  "shift quantity must be whole number of bytes"
+  .endif
+       vext.8  \vd, \vz, \vn, #16 - (\nbit >> 3)
+.endm
+
+.macro vshr128 vd, vn, nbit, vz=q15
+       // Set VD to VN shifted right by NBIT.  Assume VZ (default q15) is
+       // all-bits-zero.  NBIT must be a multiple of 8.
+  .if \nbit&3 != 0
+       .error  "shift quantity must be whole number of bytes"
+  .endif
+       vext.8  \vd, \vn, \vz, #\nbit >> 3
+.endm
+
 // Apply decoration decor to register name reg.
 #define _REGFORM(reg, decor) _GLUE(_REGFORM_, reg)(decor)
 
@@ -972,7 +901,7 @@ name:
 #define QQ(qlo, qhi) D0(qlo)-D1(qhi)
 
 // Stack management and unwinding.
-.macro setfp   fp, offset = 0
+.macro setfp   fp=r11, offset=0
   .if \offset == 0
        mov     \fp, sp
          .setfp \fp, sp
@@ -984,7 +913,7 @@ name:
        .L$_frameptr_p = -1
 .endm
 
-.macro _dropfp fp, offset = 0
+.macro _dropfp fp, offset=0
   .if \offset == 0
        mov     sp, \fp
   .else
@@ -1005,12 +934,12 @@ name:
 .endm
 
 .macro pushreg rr:vararg
-       stmfd   sp!, {\rr}
+       push    {\rr}
          .save {\rr}
 .endm
 
 .macro popreg  rr:vararg
-       ldmfd   sp!, {\rr}
+       pop     {\rr}
 .endm
 
 .macro pushvfp rr:vararg
@@ -1056,8 +985,31 @@ name:
 #endif
 .endm
 
+.macro vzero   vz=v31
+       // Set VZ (default v31) to zero.
+       dup     \vz\().4s, wzr
+.endm
+
+.macro vshl128 vd, vn, nbit, vz=v31
+       // Set VD to VN shifted left by NBIT.  Assume VZ (default v31) is
+       // all-bits-zero.  NBIT must be a multiple of 8.
+  .if \nbit&3 != 0
+       .error  "shift quantity must be whole number of bytes"
+  .endif
+       ext     \vd\().16b, \vz\().16b, \vn\().16b, #16 - (\nbit >> 3)
+.endm
+
+.macro vshr128 vd, vn, nbit, vz=v31
+       // Set VD to VN shifted right by NBIT.  Assume VZ (default v31) is
+       // all-bits-zero.  NBIT must be a multiple of 8.
+  .if \nbit&3 != 0
+       .error  "shift quantity must be whole number of bytes"
+  .endif
+       ext     \vd\().16b, \vn\().16b, \vz\().16b, #\nbit >> 3
+.endm
+
 // Stack management and unwinding.
-.macro setfp   fp, offset = 0
+.macro setfp   fp=x29, offset=0
   // If you're just going through the motions with a fixed-size stack frame,
   // then you want to say `add x29, sp, #OFFSET' directly, which will avoid
   // pointlessly restoring sp later.
@@ -1073,7 +1025,7 @@ name:
        .L$_frameptr_p = -1
 .endm
 
-.macro _dropfp fp, offset = 0
+.macro _dropfp fp, offset=0
   .if \offset == 0
        mov     sp, \fp
          .cfi_def_cfa_register sp
@@ -1096,8 +1048,8 @@ name:
          .cfi_adjust_cfa_offset -\n
 .endm
 
-.macro pushreg x, y=
-  .ifeqs "\y", ""
+.macro pushreg x, y=nil
+  .ifeqs "\y", "nil"
        str     \x, [sp, #-16]!
          .cfi_adjust_cfa_offset +16
          .cfi_rel_offset \x, 0
@@ -1109,8 +1061,8 @@ name:
   .endif
 .endm
 
-.macro popreg  x, y=
-  .ifeqs "\y", ""
+.macro popreg  x, y=nil
+  .ifeqs "\y", "nil"
        ldr     \x, [sp], #16
          .cfi_restore \x
          .cfi_adjust_cfa_offset -16
@@ -1122,9 +1074,9 @@ name:
   .endif
 .endm
 
-.macro savereg x, y, z=
-  .ifeqs "\z", ""
-       str     \x, [sp, #\y]
+.macro savereg x, y, z=nil
+  .ifeqs "\z", "nil"
+       str     \x, [sp, \y]
          .cfi_rel_offset \x, \y
   .else
        stp     \x, \y, [sp, #\z]
@@ -1133,9 +1085,9 @@ name:
   .endif
 .endm
 
-.macro rstrreg x, y, z=
-  .ifeqs "\z", ""
-       ldr     \x, [sp, #\y]
+.macro rstrreg x, y, z=nil
+  .ifeqs "\z", "nil"
+       ldr     \x, [sp, \y]
          .cfi_restore \x
   .else
        ldp     \x, \y, [sp, #\z]
@@ -1164,7 +1116,11 @@ name:
 #endif
 
 #ifndef F
-#  define F(name) name
+#  ifdef SYM_USCORE
+#    define F(name) _##name
+#  else
+#    define F(name) name
+#  endif
 #endif
 
 #ifndef TYPE_FUNC
@@ -1181,3 +1137,5 @@ name:
 #endif
 
 ///----- That's all, folks --------------------------------------------------
+
+#endif
index f0531ea..131e3fd 100644 (file)
 #  define EFLAGS_ID (1u << 21)
 #  define CPUID1D_SSE2 (1u << 26)
 #  define CPUID1D_FXSR (1u << 24)
+#  define CPUID1C_PCLMUL (1u << 1)
+#  define CPUID1C_SSSE3 (1u << 9)
 #  define CPUID1C_AESNI (1u << 25)
+#  define CPUID1C_AVX (1u << 28)
 #  define CPUID1C_RDRAND (1u << 30)
 
 struct cpuid { unsigned a, b, c, d; };
@@ -334,14 +337,16 @@ static unsigned hwcaps = 0;
        _(ARM_NEON, "arm:neon")                                         \
        _(ARM_V4, "arm:v4")                                             \
        _(ARM_D32, "arm:d32")                                           \
-       _(ARM_AES, "arm:aes")
+       _(ARM_AES, "arm:aes")                                           \
+       _(ARM_PMULL, "arm:pmull")
 #endif
 #if CPUFAM_ARM64
 #  define WANTAUX(_)                                                   \
        WANT_AT_HWCAP(_)
 #  define CAPMAP(_)                                                    \
        _(ARM_NEON, "arm:neon")                                         \
-       _(ARM_AES, "arm:aes")
+       _(ARM_AES, "arm:aes")                                           \
+       _(ARM_PMULL, "arm:pmull")
 #endif
 
 /* Build the bitmask for `hwcaps' from the `CAPMAP' list. */
@@ -455,10 +460,14 @@ static void probe_hwcaps(void)
 #  ifdef HWCAP2_AES
   if (probed.hwcap2 & HWCAP2_AES) hw |= HF_ARM_AES;
 #  endif
+#  ifdef HWCAP2_PMULL
+  if (probed.hwcap2 & HWCAP2_PMULL) hw |= HF_ARM_PMULL;
+#  endif
 #endif
 #if CPUFAM_ARM64
   if (probed.hwcap & HWCAP_ASIMD) hw |= HF_ARM_NEON;
   if (probed.hwcap & HWCAP_AES) hw |= HF_ARM_AES;
+  if (probed.hwcap & HWCAP_PMULL) hw |= HF_ARM_PMULL;
 #endif
 
   /* Store the bitmask of features we probed for everyone to see. */
@@ -600,6 +609,15 @@ int cpu_feature_p(int feat)
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_RDRAND, "x86:rdrand",
                 cpuid_features_p(0, CPUID1C_RDRAND) && rdrand_works_p());
+    CASE_CPUFEAT(X86_AVX, "x86:avx",
+                cpuid_features_p(0, CPUID1C_AVX) &&
+                xmm_registers_available_p());
+    CASE_CPUFEAT(X86_SSSE3, "x86:ssse3",
+                cpuid_features_p(0, CPUID1C_SSSE3) &&
+                xmm_registers_available_p());
+    CASE_CPUFEAT(X86_PCLMUL, "x86:pclmul",
+                cpuid_features_p(0, CPUID1C_PCLMUL) &&
+                xmm_registers_available_p());
 #endif
 #ifdef CAPMAP
 #  define FEATP__CASE(feat, tok)                                       \
index f778068..7c08382 100644 (file)
@@ -181,7 +181,11 @@ enum {
   CPUFEAT_ARM_V4,                      /* VFPv4 and/or SIMD v2 */
   CPUFEAT_ARM_D32,                     /* 32 double registers, not 16 */
   CPUFEAT_X86_RDRAND,                  /* Built-in entropy source */
-  CPUFEAT_ARM_AES                      /* AES instructions */
+  CPUFEAT_ARM_AES,                     /* AES instructions */
+  CPUFEAT_X86_AVX,                     /* AVX 1 (i.e., 256-bit YMM regs) */
+  CPUFEAT_X86_SSSE3,                   /* Supplementary SSE 3 */
+  CPUFEAT_X86_PCLMUL,                  /* Carry-less multiplication */
+  CPUFEAT_ARM_PMULL                    /* Polynomial multiplication */
 };
 
 extern int cpu_feature_p(int /*feat*/);
index 8e5e2ca..13d850a 100644 (file)
@@ -81,4 +81,43 @@ size_t keysz(size_t sz, const octet *ksz)
   return (0);
 }
 
+/* --- @keysz_pad@ --- *
+ *
+ * Arguments:  @size_t sz@ = a proposed key size
+ *             @const octet *ksz@ = pointer to key size table
+ *
+ * Returns:    A key size, at least as large as @sz@, or zero if no such
+ *             size is available.
+ */
+
+size_t keysz_pad(size_t sz, const octet *ksz)
+{
+  unsigned op = ksz[0]&KSZ_OPMASK;
+  unsigned wd = (ksz[0]&KSZ_16BIT) ? 2 : 1;
+  unsigned t, u, v;
+
+  ksz++;
+#define ARG(i) (wd == 1 ? ksz[i] : LOAD16(ksz + 2*i))
+  switch (op) {
+    case KSZ_ANY: return (sz);
+    case KSZ_RANGE:
+      t = ARG(1); u = ARG(2); v = ARG(3);
+      if (v) { sz += v - 1; sz -= sz%v; }
+      if (u && sz > u) return (0);
+      if (sz < t) return (t);
+      return (sz);
+    case KSZ_SET:
+      u = 0;
+      for (;;) {
+       t = ARG(0); ksz += wd; if (!t) break;
+       if (sz <= t && (!u || u > t)) u = t;
+      }
+      return (u);
+  }
+#undef ARG
+
+  assert(((void)"bad key size table", 0));
+  return (0);
+}
+
 /*----- That's all, folks -------------------------------------------------*/
index b83203b..4ad772a 100644 (file)
@@ -88,6 +88,17 @@ extern size_t keysz(size_t /*sz*/, const octet */*ksz*/);
 #define KSZ_ASSERT(pre, sz)                                            \
   assert(((void)"Bad key size for " #pre, KSZ_CHECK(pre, sz)))
 
+/* --- @keysz_pad@ --- *
+ *
+ * Arguments:  @size_t sz@ = a proposed key size
+ *             @const octet *ksz@ = pointer to key size table
+ *
+ * Returns:    A key size, at least as large as @sz@, or zero if no such
+ *             size is available.
+ */
+
+extern size_t keysz_pad(size_t /*sz*/, const octet */*ksz*/);
+
 /*----- Key size conversions ----------------------------------------------*/
 
 /* --- @keysz_fromdl@, @_fromschnorr@, @_fromif@, @_fromec@ --- *
diff --git a/base/regdump-arm.S b/base/regdump-arm.S
new file mode 100644 (file)
index 0000000..963a60e
--- /dev/null
@@ -0,0 +1,184 @@
+/// -*- mode: asm; asm-comment-char: ?/ -*-
+///
+/// Register dump and debugging for 32-bit ARM
+///
+/// (c) 2019 Straylight/Edgeware
+///
+
+///----- Licensing notice ---------------------------------------------------
+///
+/// This file is part of Catacomb.
+///
+/// Catacomb is free software: you can redistribute it and/or modify it
+/// under the terms of the GNU Library General Public License as published
+/// by the Free Software Foundation; either version 2 of the License, or
+/// (at your option) any later version.
+///
+/// Catacomb is distributed in the hope that it will be useful, but
+/// WITHOUT ANY WARRANTY; without even the implied warranty of
+/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+/// Library General Public License for more details.
+///
+/// You should have received a copy of the GNU Library General Public
+/// License along with Catacomb.  If not, write to the Free Software
+/// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+/// USA.
+
+///--------------------------------------------------------------------------
+/// Preliminaries.
+
+#include "config.h"
+#include "asm-common.h"
+#include "regdump.h"
+
+       .arch   armv7-a
+       .fpu    neon
+
+       .text
+
+///--------------------------------------------------------------------------
+/// Main code.
+
+FUNC(regdump_gpsave)
+  endprologue
+       // On entry, r13 should point to `REGDUMP_GPSIZE' bytes of
+       // word-aligned storage to be the general-purpose save area, with r12
+       // and r14 already saved.  On exit, the initial registers are saved
+       // in this space, and modified: r4 points to the general-purpose save
+       // area, r6 holds the focus address (possibly already saved), r0
+       // contains the number of bytes required in the extended save area,
+       // and other general-purpose registers are clobbered or used to
+       // communicate with `regdump_xtsave' below.  Doing anything other
+       // than lowering the stack pointer and calling `regdump_xtsave' is
+       // not recommended.
+
+       // Save the easy registers.
+       stmia   r13, {r0-r11}
+       mov     r4, r13
+
+       // Determine the previous stack pointer and save it.
+       add     r0, r4, #REGDUMP_GPSIZE
+       str     r0, [r4, #13*4]
+
+       // Capture the status flags and return address.  If the return
+       // address has its low bit set, then the caller was in Thumb state:
+       // clear the bit from the reconstructed PC, and set the corresponding
+       // CPSR bit.
+       mrs     r0, cpsr
+       tst     r14, #1
+       bic     r1, r14, #1
+       orrne   r0, r0, #0x00000020
+       str     r0, [r13, #4*REGIX_CPSR]
+       str     r1, [r13, #15*4]
+
+       // Load the focus address and save it as r6.
+       ldr     r6, [r4, #4*REGIX_ADDR]
+
+       // Determine the extended save area size.
+       ldgot
+       mov     r0, #8 + 8
+       leaext  r12, regdump__flags
+       ldr     r12, [r12]
+       tst     r12, #REGF_VFP
+       addne   r0, r0, #REGDUMP_FPSIZE_D16
+       tstne   r12, #REGF_D32
+       addne   r0, r0, #REGDUMP_FPSIZE_D32 - REGDUMP_FPSIZE_D16
+
+       // Done.
+       bx      r14
+
+ENDFUNC
+
+FUNC(regdump_gprstr)
+  endprologue
+       // On entry, r4 points to a general-purpose save area, established by
+       // `regdump_gpsave'.  On exit, the general-purpose registers (other
+       // than r13 and r14) are restored to their original values.
+
+       // Restore the processor flags.
+       ldr     r0, [r4, #4*REGIX_CPSR]
+       msr     cpsr_fs, r0
+
+       // Load the easy registers.
+       ldmia   r4, {r0-r12}
+
+       // Done.
+       bx      r14
+
+ENDFUNC
+
+FUNC(regdump_xtsave)
+  endprologue
+       // On entry, r13 points to an extended save area, of size determined
+       // by `regdump_gpsave' above.  On exit, the save area is filled in
+       // and a handy map placed at its base.
+
+       // Set up the map/extended save area pointer.
+       add     r5, r13, #7
+       bic     r5, r5, #7
+
+       // Start by filling in the easy part of the map.
+       str     r4, [r5, #regmap_gp]
+
+       // Fetch the flags explaining what to do.
+       ldgot
+       leaext  r12, regdump__flags
+       ldr     r12, [r12]
+
+       // Figure out whether there are VFP/NEON registers.
+       tst     r12, #REGF_VFP
+       moveq   r3, #0
+       addne   r3, r5, #regmap_size
+       str     r3, [r5, #regmap_fp]
+       beq     9f
+
+       // Get the FP status register.
+       vmrs    r0, fpscr
+       str     r0, [r3], #8
+
+       // At least the first 16.
+       vstmia  r3!, {d0-d15}
+
+       // Maybe the other 16 too.
+       tst     r12, #REGF_D32
+       vstmiane r3!, {d16-d31}
+
+       // Done.
+9:     bx      r14
+
+ENDFUNC
+
+FUNC(regdump_xtrstr)
+  endprologue
+       // On entry, r5 points to a register-save map.  On exit, the extended
+       // registers are restored from the save area, r4 (pointing to the
+       // general-purpose save area) is preserved, and the other general
+       // registers are clobbered.
+
+       // Fetch the flags explaining what to do.
+       ldgot
+       leaext  r12, regdump__flags
+       ldr     r12, [r12]
+
+       // Figure out if there are VFP/NEON registers.
+       tst     r12, #REGF_VFP
+       beq     9f
+       ldr     r3, [r5, #regmap_fp]
+
+       // Load the FP status register.
+       ldr     r0, [r3], #8
+       vmsr    fpscr, r0
+
+       // Load the first 16 registers.
+       vldmia  r3!, {d0-d15}
+
+       // And maybe the other 16.
+       tst     r12, #REGF_D32
+       vldmiane r3!, {d16-d31}
+
+       // Done.
+9:     bx      r14
+
+ENDFUNC
+
+///----- That's all, folks --------------------------------------------------
diff --git a/base/regdump-arm64.S b/base/regdump-arm64.S
new file mode 100644 (file)
index 0000000..81c9f8e
--- /dev/null
@@ -0,0 +1,204 @@
+/// -*- mode: asm; asm-comment-char: ?/ -*-
+///
+/// Register dump and debugging for 64-bit ARM
+///
+/// (c) 2019 Straylight/Edgeware
+///
+
+///----- Licensing notice ---------------------------------------------------
+///
+/// This file is part of Catacomb.
+///
+/// Catacomb is free software: you can redistribute it and/or modify it
+/// under the terms of the GNU Library General Public License as published
+/// by the Free Software Foundation; either version 2 of the License, or
+/// (at your option) any later version.
+///
+/// Catacomb is distributed in the hope that it will be useful, but
+/// WITHOUT ANY WARRANTY; without even the implied warranty of
+/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+/// Library General Public License for more details.
+///
+/// You should have received a copy of the GNU Library General Public
+/// License along with Catacomb.  If not, write to the Free Software
+/// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+/// USA.
+
+///--------------------------------------------------------------------------
+/// Preliminaries.
+
+#include "config.h"
+#include "asm-common.h"
+#include "regdump.h"
+
+       .arch   armv8-a
+
+       .text
+
+///--------------------------------------------------------------------------
+/// Main code.
+
+FUNC(regdump_gpsave)
+  endprologue
+       // On entry, sp should point to `REGDUMP_GPSIZE' bytes of
+       // doubleword-aligned storage to be the general-purpose save area,
+       // with x16, x17, and x30 already saved.  On exit, the initial
+       // registers are saved in this space, and modified: x20 points to the
+       // general-purpose save area, x22 holds the focus address (possibly
+       // already saved), x0 contains the number of bytes required in the
+       // extended save area, and other general-purpose registers are
+       // clobbered or used to communicate with `regdump_xtsave' below.
+       // Doing anything other than lowering the stack pointer and calling
+       // `regdump_xtsave' is not recommended.
+
+       // Save the easy registers.
+       stp     x0, x1, [sp, #0]
+       stp     x2, x3, [sp, #16]
+       stp     x4, x5, [sp, #32]
+       stp     x6, x7, [sp, #48]
+       stp     x8, x9, [sp, #64]
+       stp     x10, x11, [sp, #80]
+       stp     x12, x13, [sp, #96]
+       stp     x14, x15, [sp, #112]
+       stp     x18, x19, [sp, #144]
+       stp     x20, x21, [sp, #160]
+       stp     x22, x23, [sp, #176]
+       stp     x24, x25, [sp, #192]
+       stp     x26, x27, [sp, #208]
+       stp     x28, x29, [sp, #224]
+
+       mov     x20, sp
+
+       // Determine the previous stack pointer and save it.
+       add     x0, x20, #REGDUMP_GPSIZE
+       str     x0, [x20, #31*8]
+
+       // Capture the status flags.
+       mrs     x0, nzcv
+       str     x0, [x20, #8*REGIX_NZCV]
+
+       // Set the return address as our PC.
+       str     x30, [x20, #8*REGIX_PC]
+
+       // Load the focus address and save it as x22.
+       ldr     x22, [x20, #8*REGIX_ADDR]
+
+       // Determine the extended save area size.
+       mov     x0, #REGDUMP_FPSIZE
+
+       // Done.
+       ret
+
+ENDFUNC
+
+FUNC(regdump_gprstr)
+  endprologue
+       // On entry, x20 points to a general-purpose save area, established
+       // by `regdump_gpsave'.  On exit, the general-purpose registers
+       // (other than x30 and sp) are restored to their original values.
+
+       // Restore the processor flags.
+       ldr     w0, [x20, #8*REGIX_NZCV]
+       msr     nzcv, x0
+
+       // Load the easy registers.
+       ldp     x0, x1, [sp, #0]
+       ldp     x2, x3, [sp, #16]
+       ldp     x4, x5, [sp, #32]
+       ldp     x6, x7, [sp, #48]
+       ldp     x8, x9, [sp, #64]
+       ldp     x10, x11, [sp, #80]
+       ldp     x12, x13, [sp, #96]
+       ldp     x14, x15, [sp, #112]
+       ldp     x16, x17, [sp, #128]
+       ldp     x18, x19, [sp, #144]
+       ldp     x20, x21, [sp, #160]
+       ldp     x22, x23, [sp, #176]
+       ldp     x24, x25, [sp, #192]
+       ldp     x26, x27, [sp, #208]
+       ldp     x28, x29, [sp, #224]
+
+       // Done.
+       ret
+
+ENDFUNC
+
+FUNC(regdump_xtsave)
+  endprologue
+       // On entry, sp points to an extended save area, of size determined
+       // by `regdump_gpsave' above.  On exit, the save area is filled in
+       // and a handy map placed at its base.
+
+       // Set up the map/extended save area pointer.
+       mov     x21, sp
+
+       // Start by filling in the easy part of the map.
+       add     x0, x21, #regmap_size
+       stp     x20, x0, [x21]
+
+       // Get the FP status register.
+       mrs     x1, fpsr
+       mrs     x2, fpcr
+       stp     w1, w2, [x0], #8
+
+       // Store the SIMD registers.
+       stp     q0, q1, [x0, #0]
+       stp     q2, q3, [x0, #32]
+       stp     q4, q5, [x0, #64]
+       stp     q6, q7, [x0, #96]
+       stp     q8, q9, [x0, #128]
+       stp     q10, q11, [x0, #160]
+       stp     q12, q13, [x0, #192]
+       stp     q14, q15, [x0, #224]
+       stp     q16, q17, [x0, #256]
+       stp     q18, q19, [x0, #288]
+       stp     q20, q21, [x0, #320]
+       stp     q22, q23, [x0, #352]
+       stp     q24, q25, [x0, #384]
+       stp     q26, q27, [x0, #416]
+       stp     q28, q29, [x0, #448]
+       stp     q30, q31, [x0, #480]
+
+       // Done.
+       ret
+
+ENDFUNC
+
+FUNC(regdump_xtrstr)
+  endprologue
+       // On entry, x21 points to a register-save map.  On exit, the
+       // extended registers are restored from the save area, x20 (pointing
+       // to the general-purpose save area) is preserved, and the other
+       // general registers are clobbered.
+
+       ldr     x0, [x21, #regmap_fp]
+
+       // Load the FP status and control registers.
+       ldp     w1, w2, [x0], #8
+       msr     fpsr, x1
+       msr     fpcr, x2
+
+       // Load the SIMD registers.
+       ldp     q0, q1, [x0, #0]
+       ldp     q2, q3, [x0, #32]
+       ldp     q4, q5, [x0, #64]
+       ldp     q6, q7, [x0, #96]
+       ldp     q8, q9, [x0, #128]
+       ldp     q10, q11, [x0, #160]
+       ldp     q12, q13, [x0, #192]
+       ldp     q14, q15, [x0, #224]
+       ldp     q16, q17, [x0, #256]
+       ldp     q18, q19, [x0, #288]
+       ldp     q20, q21, [x0, #320]
+       ldp     q22, q23, [x0, #352]
+       ldp     q24, q25, [x0, #384]
+       ldp     q26, q27, [x0, #416]
+       ldp     q28, q29, [x0, #448]
+       ldp     q30, q31, [x0, #480]
+
+       // Done.
+       ret
+
+ENDFUNC
+
+///----- That's all, folks --------------------------------------------------
diff --git a/base/regdump-x86ish.S b/base/regdump-x86ish.S
new file mode 100644 (file)
index 0000000..e4dd8e8
--- /dev/null
@@ -0,0 +1,277 @@
+/// -*- mode: asm; asm-comment-char: ?/ -*-
+///
+/// Register dump and debugging for x86
+///
+/// (c) 2019 Straylight/Edgeware
+///
+
+///----- Licensing notice ---------------------------------------------------
+///
+/// This file is part of Catacomb.
+///
+/// Catacomb is free software: you can redistribute it and/or modify it
+/// under the terms of the GNU Library General Public License as published
+/// by the Free Software Foundation; either version 2 of the License, or
+/// (at your option) any later version.
+///
+/// Catacomb is distributed in the hope that it will be useful, but
+/// WITHOUT ANY WARRANTY; without even the implied warranty of
+/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+/// Library General Public License for more details.
+///
+/// You should have received a copy of the GNU Library General Public
+/// License along with Catacomb.  If not, write to the Free Software
+/// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+/// USA.
+
+///--------------------------------------------------------------------------
+/// Preliminaries.
+
+#include "config.h"
+#include "asm-common.h"
+#include "regdump.h"
+
+       .text
+       .arch   pentium4
+       .arch   .xsave
+
+///--------------------------------------------------------------------------
+/// Main code.
+
+FUNC(regdump_gpsave)
+  endprologue
+       // On entry, r/esp should point to a return address and
+       // `REGDUMP_GPSIZE' bytes of word-aligned storage to be the
+       // general-purpose save area, with flags saved in the bottom word,
+       // r/eax saved in the fourth, and (on 32-bit x86) ebx in the fifth.
+       // On exit, the initial registers are saved in this space, and
+       // modified: r/ebp points to the general-purpose save area, ecx
+       // contains the number of bytes required in the extended save area,
+       // ebx is preserved on 32-bit x86, and other general-purpose
+       // registers are clobbered or used to communicate with
+       // `regdump_xtsave' below.  Doing anything other than lowering the
+       // stack pointer and calling `regdump_xtsave' is not recommended.
+
+       // Other code will insist that df is clear.
+       cld
+
+       // Save r/ebp and establish it pointing to the save area.
+       mov     [R_sp(r) + WORDSZ + REGIX_BP*WORDSZ], R_bp(r)
+       lea     R_bp(r), [R_sp(r) + WORDSZ]
+
+       // Save the other easy general-purpose registers.
+#if !CPUFAM_X86
+       mov     [R_bp(r) + REGIX_BX*WORDSZ], R_b(r)
+#endif
+       mov     [R_bp(r) + REGIX_CX*WORDSZ], R_c(r)
+       mov     [R_bp(r) + REGIX_DX*WORDSZ], R_d(r)
+       mov     [R_bp(r) + REGIX_SI*WORDSZ], R_si(r)
+       mov     [R_bp(r) + REGIX_DI*WORDSZ], R_di(r)
+#if CPUFAM_AMD64
+       mov     [R_bp(r) + REGIX_R8*WORDSZ], R_r8(r)
+       mov     [R_bp(r) + REGIX_R9*WORDSZ], R_r9(r)
+       mov     [R_bp(r) + REGIX_R10*WORDSZ], R_r10(r)
+       mov     [R_bp(r) + REGIX_R11*WORDSZ], R_r11(r)
+       mov     [R_bp(r) + REGIX_R12*WORDSZ], R_r12(r)
+       mov     [R_bp(r) + REGIX_R13*WORDSZ], R_r13(r)
+       mov     [R_bp(r) + REGIX_R14*WORDSZ], R_r14(r)
+       mov     [R_bp(r) + REGIX_R15*WORDSZ], R_r15(r)
+#endif
+
+       // Determine the previous stack pointer and save it.
+#if CPUFAM_AMD64 && ABI_SYSV
+       lea     R_a(r), [R_bp(r) + 128 + REGDUMP_GPSIZE]
+#else
+       lea     R_a(r), [R_bp(r) + REGDUMP_GPSIZE]
+#endif
+       mov     [R_bp(r) + REGIX_SP*WORDSZ], R_a(r)
+
+       // Collect the return address and save it as r/eip.
+       mov     R_a(r), [R_sp(r)]
+       mov     [R_bp(r) + REGIX_IP*WORDSZ], R_a(r)
+
+       // Save the segment registers.
+       lea     R_a(r), [R_bp(r) + REGIX_GPLIM*WORDSZ]
+       mov     [R_a(r) + 2*REGIX_CS], cs
+       mov     [R_a(r) + 2*REGIX_DS], ds
+       mov     [R_a(r) + 2*REGIX_SS], ss
+       mov     [R_a(r) + 2*REGIX_ES], es
+       mov     [R_a(r) + 2*REGIX_FS], fs
+       mov     [R_a(r) + 2*REGIX_GS], gs
+
+       // Determine the extended save area size.  Preserve ebx on 32-bit x86
+       // here, because the caller needs it for PLT-indirect calls.
+#if CPUFAM_X86
+       push    ebx
+#endif
+       mov     eax, 0x01
+       cpuid
+       test    ecx, 1 << 26
+       je      1f
+
+       mov     eax, 0x0d
+       mov     ecx, 0x00
+       cpuid
+       add     ecx, regmap_size + 64 // map + align
+       jmp     8f
+
+1:     mov     ecx, 512 + regmap_size + 16 // fxsave + map + align
+
+       // Done.
+8:
+#if CPUFAM_X86
+       pop     ebx
+#endif
+       ret
+
+ENDFUNC
+
+FUNC(regdump_gprstr)
+  endprologue
+       // On entry, r/ebp points to a general-purpose save area, established
+       // by `regdump_gpsave'.  On exit, the general-purpose registers
+       // (other than the stack pointer) are restored to their original
+       // values.
+
+       // We assume nobody actually fiddled with the segment registers.  So
+       // just the actual integer registers to do.
+       mov     R_a(r), [R_bp(r) + REGIX_AX*WORDSZ]
+       mov     R_b(r), [R_bp(r) + REGIX_BX*WORDSZ]
+       mov     R_c(r), [R_bp(r) + REGIX_CX*WORDSZ]
+       mov     R_d(r), [R_bp(r) + REGIX_DX*WORDSZ]
+       mov     R_si(r), [R_bp(r) + REGIX_SI*WORDSZ]
+       mov     R_di(r), [R_bp(r) + REGIX_DI*WORDSZ]
+#if CPUFAM_AMD64
+       mov     R_r8(r), [R_bp(r) + REGIX_R8*WORDSZ]
+       mov     R_r9(r), [R_bp(r) + REGIX_R9*WORDSZ]
+       mov     R_r10(r), [R_bp(r) + REGIX_R10*WORDSZ]
+       mov     R_r11(r), [R_bp(r) + REGIX_R11*WORDSZ]
+       mov     R_r12(r), [R_bp(r) + REGIX_R12*WORDSZ]
+       mov     R_r13(r), [R_bp(r) + REGIX_R13*WORDSZ]
+       mov     R_r14(r), [R_bp(r) + REGIX_R14*WORDSZ]
+       mov     R_r15(r), [R_bp(r) + REGIX_R15*WORDSZ]
+#endif
+       mov     R_bp(r), [R_bp(r) + REGIX_BP*WORDSZ]
+
+       // Done.
+       ret
+
+ENDFUNC
+
+#ifdef CPUFAM_AMD64
+#  define fxsave fxsave64
+#  define fxrstor fxrstor64
+#  define xsave xsave64
+#  define xrstor xrstor64
+#endif
+
+FUNC(regdump_xtsave)
+  endprologue
+       // On entry, r/esp points to a return address and extended save area,
+       // of size determined by `regdump_gpsave' above.  On exit, the save
+       // area is filled in and a handy map placed at its base, the x87
+       // floating-point state is reset, r/ebp is left pointing to the
+       // register map, ebx is preserved on 32-bit x86, and the other
+       // general registers are clobbered.
+
+       // Start by filling in the easy parts of the map.
+       mov     [R_sp(r) + WORDSZ + regmap_gp], R_bp(r)
+       lea     R_bp(r), [R_sp(r) + WORDSZ]
+
+       xor     eax, eax                // clears rax too on amd64
+       mov     [R_bp(r) + regmap_avx], R_a(r)
+
+       // Find out whether we use `xsave'.  (Preserve ebx.)
+#if CPUFAM_X86
+       push    ebx
+#endif
+       mov     eax, 0x01
+       cpuid
+       test    ecx, 1 << 26
+       je      5f
+
+       // We have the `xsave' machinery.  Select the base address.
+       lea     R_si(r), [R_sp(r) + WORDSZ + regmap_size + 63]
+       and     R_si(r), ~63
+       mov     [R_bp(r) + regmap_fx], R_si(r)
+
+       // Clear out the header area.
+       xor     eax, eax
+       lea     R_di(r), [R_si(r) + 512]
+       mov     ecx, 16
+       rep stosd
+
+       // Save the registers.
+       mov     eax, 0x00000007
+       xor     edx, edx
+       xsave   [R_si(r)]
+
+       // Establish the AVX pointer, if available.
+       test    dword ptr [R_si(r) + 512], 4 // = xstate_bv
+       je      8f
+
+       mov     eax, 13
+       mov     ecx, 2
+       cpuid
+       add     R_b(r), R_si(r)
+       mov     [R_bp(r) + regmap_avx], R_b(r)
+
+       jmp     8f
+
+       // We have only `fxsave'.  Set the base address.
+5:     lea     R_si(r), [R_sp(r) + WORDSZ + regmap_size + 15]
+       and     R_si(r), ~15
+       mov     [R_bp(r) + regmap_fx], R_si(r)
+
+       // Save the registers.
+       fxsave  [R_si(r)]
+
+       // Clear the x87 state; otherwise it can cause trouble later.
+8:     fninit
+
+       // Done.
+#if CPUFAM_X86
+       pop     ebx
+#endif
+       ret
+
+ENDFUNC
+
+FUNC(regdump_xtrstr)
+  endprologue
+       // On entry, r/ebp points to a register-save map.  On exit, the
+       // extended registers are restored from the save area; r/ebp is left
+       // pointing to the general-purpose save area, ebx is preserved on
+       // 32-bit x86, and the other general registers are clobbered.
+
+       // Find the extended register dump.
+       mov     R_si(r), [R_bp(r) + regmap_fx]
+
+       // Probe to find out whether we have `xsave'.
+#if CPUFAM_X86
+       push    ebx
+#endif
+       mov     eax, 0x01
+       cpuid
+       test    ecx, 1 << 26
+       je      1f
+
+       // We have the `xsave' machinery.
+       mov     eax, 0x00000007
+       xor     edx, edx
+       xrstor  [R_si(r)]
+       jmp     8f
+
+       // We must fake it up.
+1:     fxrstor [R_si(r)]
+
+       // Done.
+8:     mov     R_bp(r), [R_bp(r) + regmap_gp]
+#if CPUFAM_X86
+       pop     ebx
+#endif
+       ret
+
+ENDFUNC
+
+///----- That's all, folks --------------------------------------------------
diff --git a/base/regdump.c b/base/regdump.c
new file mode 100644 (file)
index 0000000..d4f5fde
--- /dev/null
@@ -0,0 +1,945 @@
+/* -*-c-*-
+ *
+ * Register dumping and other diagnostic tools for assembler code
+ *
+ * (c) 2016 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/macros.h>
+
+#include "dispatch.h"
+#include "regdump.h"
+
+/*----- Low-level printing ------------------------------------------------*/
+
+/* Currently these are good for all of our targets. */
+#define STEP_8         1
+#define TY_HEX_8       uint8
+#define P_HEX_8                "0x%02x"
+#define TY_UNSGN_8     uint8
+#define P_UNSGN_8      "%3u"
+#define PV_CHR_8       " `%c'"
+#define PV_HEX_8       "  %02x"
+#define PV_UNSGN_8     "%4u"
+
+#define STEP_16                2
+#define TY_HEX_16      uint16
+#define P_HEX_16       "0x%04x"
+#define TY_UNSGN_16    uint16
+#define P_UNSGN_16     "%5u"
+#define TY_SGN_16      int16
+#define P_SGN_16       "%6d"
+#define PV_HEX_16      "   0x%04x"
+#define PV_UNSGN_16    "%9u"
+#define PV_SGN_16      "%9d"
+
+#define STEP_32                4
+#define TY_HEX_32      uint32
+#define P_HEX_32       "0x%08x"
+#define TY_UNSGN_32    uint32
+#define P_UNSGN_32     "%10u"
+#define TY_SGN_32      int32
+#define P_SGN_32       "%11d"
+#define TY_FLT_32      float
+#define P_FLT_32       "%15.9g"
+#define PV_HEX_32      "         0x%08x"
+#define PV_UNSGN_32    "%19u"
+#define PV_SGN_32      "%19d"
+#define PV_FLT_32      "%19.9g"
+
+#if ULONG_MAX >> 31 > 0xffffffff
+#  define PL64 "l"
+#else
+#  define PL64 "ll"
+#endif
+#define STEP_64                8
+#define TY_HEX_64      uint64
+#define P_HEX_64       "0x%016"PL64"x"
+#define TY_UNSGN_64    uint64
+#define P_UNSGN_64     "%20"PL64"u"
+#define TY_SGN_64      int64
+#define P_SGN_64       "%20"PL64"d"
+#define TY_FLT_64      double
+#define P_FLT_64       "%24.17g"
+#define PV_HEX_64      "                     0x%016"PL64"x"
+#define PV_UNSGN_64    "%39"PL64"u"
+#define PV_SGN_64      "%39"PL64"d"
+#define PV_FLT_64      "%39.17g"
+
+#if CPUFAM_X86
+#  define STEP_80      12
+#endif
+#if CPUFAM_AMD64
+#  define STEP_80      16
+#endif
+#define TY_FLT_80      long double
+#define P_FLT_80       "%29.21Lg"
+#define PV_FLT_80      P_FLT_80
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+#  define ARCH_FORMATS(_)                                              \
+  _(80, FLT)
+#endif
+#ifndef ARCH_FORMATS
+#  define ARCH_FORMATS(_)
+#endif
+
+#define FORMATS(_)                                                     \
+  ARCH_FORMATS(_)                                                      \
+  _(64, HEX) _(64, FLT) _(64, UNSGN) _(64, SGN)                                \
+  _(32, HEX) _(32, FLT) _(32, UNSGN) _(32, SGN)                                \
+  _(16, HEX) _(16, UNSGN) _(16, SGN)                                   \
+  _(8, HEX) _(8, CHR) _(8, UNSGN)
+
+struct fmtinfo {
+  const unsigned char *p;
+  unsigned wd, f;
+#define FMTF_VECTOR 1u
+};
+
+#define FMTFUNC_STD(w, fmt)                                            \
+  static void dump_##fmt##_##w(struct fmtinfo *fmt)                    \
+  {                                                                    \
+    TY_##fmt##_##w x = *(const TY_##fmt##_##w *)fmt->p;                        \
+                                                                       \
+    if (fmt->f&FMTF_VECTOR) printf(PV_##fmt##_##w, x);                 \
+    else printf(P_##fmt##_##w, x);                                     \
+    fmt->p += STEP_##w; fmt->wd += 8*STEP_##w;                         \
+  }
+
+#define FMTFUNC_HEX(w) FMTFUNC_STD(w, HEX)
+#define FMTFUNC_UNSGN(w) FMTFUNC_STD(w, UNSGN)
+#define FMTFUNC_SGN(w) FMTFUNC_STD(w, SGN)
+#define FMTFUNC_FLT(w) FMTFUNC_STD(w, FLT)
+#define FMTFUNC_CHR(w)
+
+static void dump_CHR_8(struct fmtinfo *fmt)
+{
+  unsigned char x = *(const unsigned char *)fmt->p;
+
+  if (x < 32 || x > 126) printf("\\x%02x", x);
+  else printf(" `%c'", x);
+  fmt->p += 1; fmt->wd += 8;
+}
+
+#define FMTFUNC(w, fmt) FMTFUNC_##fmt(w)
+FORMATS(FMTFUNC)
+#undef FMTFUNC
+
+static const struct fmttab {
+  uint32 mask;
+  void (*fmt)(struct fmtinfo *);
+} fmttab[] = {
+#define FMTTAB(wd, fmt) { REGF_##fmt | REGF_##wd, dump_##fmt##_##wd },
+  FORMATS(FMTTAB)
+#undef FMTTAB
+  { 0, 0 }
+};
+
+/*----- Common subroutines ------------------------------------------------*/
+
+/* --- @regwd@ --- *
+ *
+ * Arguments:  @uint32 f@ = format control word; see @REGF_...@
+ *
+ * Returns:    The actual width of the operand, in bits.
+ *
+ * Use:                If the operand is a vector (the @REGF_WDMASK@ field is
+ *             nonzero) then return the width it denotes; otherwise, return
+ *             the largest width implied by the @REGF_TYMASK@ field.
+ */
+
+static unsigned regwd(uint32 f)
+{
+  unsigned wd = 1 << ((f&REGF_WDMASK) >> REGF_WDSHIFT);
+
+  if (wd > 1) return (wd);
+  else if (f&REGF_80) return (80);
+  else if (f&REGF_64) return (64);
+  else if (f&REGF_32) return (32);
+  else if (f&REGF_16) return (16);
+  else if (f&REGF_8) return (8);
+  else { assert(0); return (1); }
+}
+
+/* --- @regname@ --- *
+ *
+ * Arguments:  @char *buf = pointer to output buffer@
+ *             @uint32 f@ = format control word; see @REGF_...@
+ *
+ * Returns:    Pointer to name string.
+ *
+ * Use:                Return a pointer to the name of the register implied by @f@,
+ *             or null if there is no register.  Systematic register names
+ *             can be built in the provided buffer.
+ */
+
+static const char *regname(char *buf, uint32 f)
+{
+  unsigned wd = regwd(f);
+  unsigned src = f&REGF_SRCMASK;
+  unsigned ix = (f&REGF_IXMASK) >> REGF_IXSHIFT;
+  char *p = buf;
+
+  switch (src) {
+
+    case REGSRC_ABS:
+      return (0);
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+    case REGSRC_GP:
+      if (ix == REGIX_FLAGS) {
+       if (wd == 64) *p++ = 'r';
+       else if (wd == 32) *p++ = 'e';
+       else if (wd != 16) assert(0);
+       p += sprintf(p, "flags");
+#if  CPUFAM_AMD64
+      } else if (REGIX_R8 <= ix && ix <= REGIX_R15) {
+       p += sprintf(p, "r%u", ix - REGIX_R8 + 8);
+       switch (wd) {
+         case 64:             break;
+         case 32: *p++ = 'd'; break;
+         case 16: *p++ = 'w'; break;
+         case  8: *p++ = 'l'; break;
+         default: assert(0);
+       }
+#  endif
+      } else {
+       if (wd == 64) *p++ = 'r';
+       else if (wd == 32) *p++ = 'e';
+       switch (ix) {
+         case REGIX_IP: *p++ = 'i'; *p++ = 'p'; goto longreg;
+         case REGIX_AX: *p++ = 'a'; goto shortreg;
+         case REGIX_BX: *p++ = 'b'; goto shortreg;
+         case REGIX_CX: *p++ = 'c'; goto shortreg;
+         case REGIX_DX: *p++ = 'd'; goto shortreg;
+         case REGIX_SI: *p++ = 's'; *p++ = 'i'; goto longreg;
+         case REGIX_DI: *p++ = 'd'; *p++ = 'i'; goto longreg;
+         case REGIX_BP: *p++ = 'b'; *p++ = 'p'; goto longreg;
+         case REGIX_SP: *p++ = 's'; *p++ = 'p'; goto longreg;
+         default: assert(0);
+       }
+       if (0) {
+       shortreg:
+         switch (wd) {
+           case 64:
+           case 32:
+           case 16: *p++ = 'x'; break;
+           case  8: *p++ = 'l'; break;
+           default: assert(0);
+         }
+       } else {
+       longreg:
+         switch (wd) {
+           case 64:
+           case 32:
+           case 16: break;
+           case  8: *p++ = 'l'; break;
+           default: assert(0);
+         }
+       }
+      }
+      *p++ = 0;
+      return (buf);
+
+    case REGSRC_SEG:
+      assert(wd == 16);
+      switch (ix) {
+       case REGIX_CS: sprintf(buf, "cs"); break;
+       case REGIX_DS: sprintf(buf, "ds"); break;
+       case REGIX_SS: sprintf(buf, "ss"); break;
+       case REGIX_ES: sprintf(buf, "es"); break;
+       case REGIX_FS: sprintf(buf, "fs"); break;
+       case REGIX_GS: sprintf(buf, "gs"); break;
+       default: assert(0);
+      }
+      return (buf);
+
+    case REGSRC_STMMX:
+      if (ix == REGIX_FPFLAGS) return (0);
+      if (f&REGF_80) sprintf(buf, "st(%u)", ix);
+      else sprintf(buf, "mm%u", ix);
+      return (buf);
+
+    case REGSRC_SIMD:
+      if (ix == REGIX_FPFLAGS) return (0);
+      switch (wd) {
+       case 32: case 64: case 128: sprintf(buf, "xmm%u", ix); break;
+       case 256: sprintf(buf, "ymm%u", ix); break;
+       default: assert(0);
+      }
+      return (buf);
+#endif
+
+#if CPUFAM_ARMEL
+    case REGSRC_GP:
+      if (ix == REGIX_CPSR) sprintf(buf, "cpsr");
+      else if (ix == 15) sprintf(buf, "pc");
+      else sprintf(buf, "r%u", ix);
+      return (buf);
+    case REGSRC_FP:
+      if (ix == REGIX_FPSCR) sprintf(buf, "fpscr");
+      else {
+       switch (wd) {
+         case 32: *p++ = 's'; break;
+         case 64: *p++ = 'd'; break;
+         case 128: *p++ = 'q'; break;
+         default: assert(0);
+       }
+       p += sprintf(p, "%u", ix);
+       *p++ = 0;
+      }
+      return (buf);
+#endif
+
+#if CPUFAM_ARM64
+    case REGSRC_GP:
+      if (ix == REGIX_PC) sprintf(buf, "pc");
+      else if (ix == REGIX_NZCV) sprintf(buf, "nzcv");
+      else if (ix == 31 && wd == 64) sprintf(buf, "sp");
+      else {
+       switch (wd) {
+         case 32: *p++ = 'w'; break;
+         case 64: *p++ = 'x'; break;
+         default: assert(0);
+       }
+       p += sprintf(p, "%u", ix);
+       *p++ = 0;
+      }
+      return (buf);
+    case REGSRC_FP:
+      if (ix == REGIX_FPFLAGS) sprintf(buf, "fpflags");
+      else {
+       if (f&REGF_WDMASK)
+         *p++ = 'v';
+       else switch (wd) {
+         case 8: *p++ = 'b'; break;
+         case 16: *p++ = 'h'; break;
+         case 32: *p++ = 's'; break;
+         case 64: *p++ = 'd'; break;
+         default: assert(0);
+       }
+       p += sprintf(p, "%u", ix);
+       *p++ = 0;
+      }
+      return (buf);
+#endif
+
+    default:
+      assert(0);
+      return ("???");
+  }
+}
+
+/*----- x86 and AMD64 -----------------------------------------------------*/
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+
+#if CPUFAM_X86
+#  define P_HEX_GP "0x%08x"
+#  define GP(gp) (gp).u32
+#endif
+#if CPUFAM_AMD64
+#  define P_HEX_GP "0x%016"PL64"x"
+#  define GP(gp) (gp).u64
+#endif
+
+void regdump_init(void) { ; }
+
+static void dump_flags(const char *lbl, const char *reg, gpreg f)
+{
+  printf(";; ");
+  if (lbl) printf("%s: ", lbl);
+  if (reg) printf("%s = ", reg);
+  printf(""P_HEX_GP"\n", GP(f));
+  printf(";;\t\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n",
+        (GP(f) >>  0)&1u ? '+' : '-',
+        (GP(f) >>  2)&1u ? '+' : '-',
+        (GP(f) >>  4)&1u ? '+' : '-',
+        (GP(f) >>  6)&1u ? '+' : '-',
+        (GP(f) >>  7)&1u ? '+' : '-',
+        (GP(f) >> 10)&1u ? '+' : '-',
+        (GP(f) >> 11)&1u ? '+' : '-');
+  printf(";;\t\tsystem: %ctf %cif iopl=%d %cnt "
+                       "%crf %cvm %cac %cvif %cvip %cid\n",
+        (GP(f) >>  8)&1u ? '+' : '-',
+        (GP(f) >>  9)&1u ? '+' : '-',
+        (int)((GP(f) >> 12)&1u),
+        (GP(f) >> 14)&1u ? '+' : '-',
+        (GP(f) >> 16)&1u ? '+' : '-',
+        (GP(f) >> 17)&1u ? '+' : '-',
+        (GP(f) >> 18)&1u ? '+' : '-',
+        (GP(f) >> 19)&1u ? '+' : '-',
+        (GP(f) >> 20)&1u ? '+' : '-',
+        (GP(f) >> 21)&1u ? '+' : '-');
+}
+
+static const char
+  *pcmap[] = { "sgl", "???", "dbl", "ext" },
+  *rcmap[] = { "nr", "-∞", "+∞", "0" };
+
+static void dump_fpflags(const char *lbl, const struct fxsave *fx)
+{
+  unsigned top = (fx->fsw >> 11)&7u;
+  unsigned tag = fx->ftw;
+  int skip = lbl ? strlen(lbl) + 2 : 0;
+
+  printf(";; ");
+  if (lbl) printf("%s: ", lbl);
+
+  printf("    fcw = 0x%04x: "
+        "%cim %cdm %czm %com %cum %cpm pc=%s rc=%s %cx\n",
+        fx->fcw,
+        (fx->fcw >>  0)&1u ? '+' : '-',
+        (fx->fcw >>  1)&1u ? '+' : '-',
+        (fx->fcw >>  2)&1u ? '+' : '-',
+        (fx->fcw >>  3)&1u ? '+' : '-',
+        (fx->fcw >>  4)&1u ? '+' : '-',
+        (fx->fcw >>  5)&1u ? '+' : '-',
+        pcmap[(fx->fcw >>  8)&3u],
+        rcmap[(fx->fcw >> 10)&3u],
+        (fx->fcw >> 12)&1u ? '+' : '-');
+  printf(";; %*s    fsw = 0x%04x: "
+        "%cie %cde %cze %coe %cue %cpe %csf %ces %cc0 %cc1 %cc2 %cc3 "
+        "top=%d %cb\n",
+        skip, "",
+        fx->fsw,
+        (fx->fsw >>  0)&1u ? '+' : '-',
+        (fx->fsw >>  1)&1u ? '+' : '-',
+        (fx->fsw >>  2)&1u ? '+' : '-',
+        (fx->fsw >>  3)&1u ? '+' : '-',
+        (fx->fsw >>  4)&1u ? '+' : '-',
+        (fx->fsw >>  5)&1u ? '+' : '-',
+        (fx->fsw >>  6)&1u ? '+' : '-',
+        (fx->fsw >>  7)&1u ? '+' : '-',
+        (fx->fsw >>  8)&1u ? '+' : '-',
+        (fx->fsw >>  9)&1u ? '+' : '-',
+        (fx->fsw >> 10)&1u ? '+' : '-',
+        (fx->fsw >> 14)&1u ? '+' : '-',
+        top,
+        (fx->fsw >> 15)&1u ? '+' : '-');
+  printf(";; %*s    ftw = 0x%02x\n", skip, "", tag);
+}
+
+static void dump_mxflags(const char *lbl, const struct fxsave *fx)
+{
+  printf(";; ");
+  if (lbl) printf("%s: ", lbl);
+
+  printf("  mxcsr = 0x%08x\n"
+        ";;\t\tmask = %cim %cdm %czm %com %cum %cpm\n"
+        ";;\t\t exc = %cie %cde %cze %coe %cue %cpe\n"
+        ";;\t\tmisc = %cdaz %cftz rc=%s\n",
+        fx->mxcsr,
+        (fx->mxcsr >>  7)&1u ? '+' : '-',
+        (fx->mxcsr >>  8)&1u ? '+' : '-',
+        (fx->mxcsr >>  9)&1u ? '+' : '-',
+        (fx->mxcsr >> 10)&1u ? '+' : '-',
+        (fx->mxcsr >> 11)&1u ? '+' : '-',
+        (fx->mxcsr >> 12)&1u ? '+' : '-',
+        (fx->mxcsr >>  0)&1u ? '+' : '-',
+        (fx->mxcsr >>  1)&1u ? '+' : '-',
+        (fx->mxcsr >>  2)&1u ? '+' : '-',
+        (fx->mxcsr >>  3)&1u ? '+' : '-',
+        (fx->mxcsr >>  4)&1u ? '+' : '-',
+        (fx->mxcsr >>  5)&1u ? '+' : '-',
+        (fx->mxcsr >>  6)&1u ? '+' : '-',
+        (fx->mxcsr >> 15)&1u ? '+' : '-',
+        rcmap[(fx->mxcsr >> 13)&3u]);
+}
+
+#if CPUFAM_X86
+#  define REGF_GPWD REGF_32
+#endif
+#if CPUFAM_AMD64
+#  define REGF_GPWD REGF_64
+#endif
+
+void regdump_gp(const struct regmap *map)
+{
+  unsigned i;
+
+  printf(";; General-purpose registers:\n");
+  for (i = REGIX_AX; i < REGIX_GPLIM; i++)
+    regdump(map, 0,
+           REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_GPWD | REGSRC_GP | i);
+  regdump(map, 0, REGF_HEX | REGF_GPWD | REGSRC_GP | REGIX_IP);
+
+  printf(";; Segment registers:\n");
+  for (i = 0; i < REGIX_SEGLIM; i++)
+    regdump(map, 0, REGF_HEX | REGF_16 | REGSRC_SEG | i);
+
+  printf(";; Flags:\n");
+  regdump(map, 0, REGSRC_GP | REGF_GPWD | REGIX_FLAGS);
+}
+
+void regdump_fp(const struct regmap *map)
+{
+  unsigned top = (map->fx->fsw >> 11)&7u;
+  unsigned tag = map->fx->ftw;
+  unsigned i;
+
+  printf(";; Floating-point/MMX registers:\n");
+  if (!top && tag == 0xff)
+    for (i = 0; i < 8; i++)
+      regdump(map, 0,
+             REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_CHR |
+             REGF_32 | REGF_16 | REGF_8 |
+             REGSRC_STMMX | i | (6 << REGF_WDSHIFT));
+  if (tag)
+    for (i = 0; i < 8; i++)
+      regdump(map, 0, REGF_FLT | REGF_80 | REGSRC_STMMX | i);
+
+  printf(";; Floating-point state:\n");
+  dump_fpflags(0, map->fx);
+}
+
+void regdump_simd(const struct regmap *map)
+{
+  unsigned f = REGF_HEX | REGF_FLT | REGF_UNSGN | REGF_SGN | REGF_CHR |
+    REGF_64 | REGF_32 | REGF_16 | REGF_8 |
+    REGSRC_SIMD;
+  unsigned i;
+
+  if (map->avx) f |= 8 << REGF_WDSHIFT;
+  else f |= 7 << REGF_WDSHIFT;
+
+  printf(";; SSE/AVX registers:\n");
+  for (i = 0; i < N(map->fx->xmm); i++)
+    regdump(map, 0, f | i);
+
+  printf(";; SSE/AVX floating-point state:\n");
+  dump_mxflags(0, map->fx);
+}
+
+#endif
+
+/*----- ARM32 -------------------------------------------------------------*/
+
+#if CPUFAM_ARMEL
+
+unsigned regdump__flags = 0;
+
+void regdump_init(void)
+{
+  if (cpu_feature_p(CPUFEAT_ARM_VFP)) regdump__flags |= REGF_VFP;
+  if (cpu_feature_p(CPUFEAT_ARM_D32)) regdump__flags |= REGF_D32;
+}
+
+static void dump_flags(const char *lbl, unsigned f)
+{
+  static const char
+    *modetab[] = { "?00", "?01", "?02", "?03", "?04", "?05", "?06", "?07",
+                  "?08", "?09", "?10", "?11", "?12", "?13", "?14", "?15",
+                  "usr", "fiq", "irq", "svc", "?20", "?21", "mon", "abt",
+                  "?24", "?25", "hyp", "und", "?28", "?29", "?30", "sys" },
+    *condtab[] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+                  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
+
+  printf(";; ");
+  if (lbl) printf("%s: ", lbl);
+  printf("   cpsr = 0x%08x\n", f);
+  printf(";;\t\tuser: %cn %cz %cc %cv %cq ge=%c%c%c%c\n",
+        (f >> 31)&1u ? '+' : '-',
+        (f >> 30)&1u ? '+' : '-',
+        (f >> 29)&1u ? '+' : '-',
+        (f >> 28)&1u ? '+' : '-',
+        (f >> 27)&1u ? '+' : '-',
+        (f >> 19)&1u ? '1' : '0',
+        (f >> 18)&1u ? '1' : '0',
+        (f >> 17)&1u ? '1' : '0',
+        (f >> 16)&1u ? '1' : '0');
+  printf(";;\t\tsystem: %cj it=%s:%c%c%c%c %ce %ca %ci %cf %ct m=%s\n",
+        (f >> 24)&1u ? '+' : '-',
+        condtab[(f >> 12)&15u],
+        (f >> 11)&1u ? '1' : '0',
+        (f >> 10)&1u ? '1' : '0',
+        (f >> 26)&1u ? '1' : '0',
+        (f >> 25)&1u ? '1' : '0',
+        (f >>  9)&1u ? '+' : '-',
+        (f >>  8)&1u ? '+' : '-',
+        (f >>  7)&1u ? '+' : '-',
+        (f >>  6)&1u ? '+' : '-',
+        (f >>  5)&1u ? '+' : '-',
+        modetab[(f >>  0)&31u]);
+}
+
+static void dump_fpflags(const char *lbl, unsigned f)
+{
+  static const char *rcmap[] = { "nr", "+∞", "-∞", "0" };
+
+  printf(";; ");
+  if (lbl) printf("%s: ", lbl);
+  printf("  fpscr = 0x%08x\n", f);
+  printf(";;\t\tcond: %cn %cz %cc %cv %cqc\n",
+        (f >> 31)&1u ? '+' : '-',
+        (f >> 30)&1u ? '+' : '-',
+        (f >> 29)&1u ? '+' : '-',
+        (f >> 28)&1u ? '+' : '-',
+        (f >> 27)&1u ? '+' : '-');
+  printf(";;\t\ttrap: %cide %cixe %cufe %cofe %cdze %cioe\n",
+        (f >> 15)&1u ? '+' : '-',
+        (f >> 12)&1u ? '+' : '-',
+        (f >> 11)&1u ? '+' : '-',
+        (f >> 10)&1u ? '+' : '-',
+        (f >>  9)&1u ? '+' : '-',
+        (f >>  8)&1u ? '+' : '-');
+  printf(";;\t\terror:  %cide %cixe %cufe %cofe %cdze %cioe\n",
+        (f >>  7)&1u ? '+' : '-',
+        (f >>  4)&1u ? '+' : '-',
+        (f >>  3)&1u ? '+' : '-',
+        (f >>  2)&1u ? '+' : '-',
+        (f >>  1)&1u ? '+' : '-',
+        (f >>  0)&1u ? '+' : '-');
+  printf(";;\t\tcontrol: %cahp %cdn %cfz rm=%s str=%d len=%d\n",
+        (f >> 26)&1u ? '+' : '-',
+        (f >> 25)&1u ? '+' : '-',
+        (f >> 24)&1u ? '+' : '-',
+        rcmap[(f >> 22)&3u],
+        (f >> 20)&3u,
+        (f >> 16)&7u);
+}
+
+void regdump_gp(const struct regmap *map)
+{
+  unsigned i;
+
+  printf(";; General-purpose registers:\n");
+  for (i = 0; i < 16; i++)
+    regdump(map, 0,
+           REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_32 | REGSRC_GP | i);
+
+  printf(";; Flags:\n");
+  regdump(map, 0, REGSRC_GP | REGF_32 | REGIX_CPSR);
+}
+
+void regdump_fp(const struct regmap *map)
+{
+  unsigned i, n;
+
+  if (!(regdump__flags&REGF_VFP)) {
+    printf(";; Floating-point and SIMD not available\n");
+    return;
+  }
+
+  printf(";; Floating-point/SIMD registers:\n");
+  if (regdump__flags&REGF_D32) n = 32;
+  else n = 16;
+  for (i = 0; i < n; i++)
+    regdump(map, 0,
+           REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_FLT | REGF_CHR |
+           REGF_64 | REGF_32 | REGF_16 | REGF_8 |
+           REGSRC_SIMD | i | (6 << REGF_WDSHIFT));
+
+  printf(";; Floating-point state:\n");
+  dump_fpflags(0, map->fp->fpscr);
+}
+
+void regdump_simd(const struct regmap *map) { ; }
+
+#endif
+
+/*----- ARM64 -------------------------------------------------------------*/
+
+#if CPUFAM_ARM64
+
+void regdump_init(void) { ; }
+
+static void dump_flags(const char *lbl, unsigned f)
+{
+  printf(";; ");
+  if (lbl) printf("%s: ", lbl);
+  printf("   nzcv = 0x%08x\n", f);
+  printf(";;\t\tuser: %cn %cz %cc %cv\n",
+        (f >> 31)&1u ? '+' : '-',
+        (f >> 30)&1u ? '+' : '-',
+        (f >> 29)&1u ? '+' : '-',
+        (f >> 28)&1u ? '+' : '-');
+}
+
+static void dump_fpflags(const char *lbl, const struct fpsave *fp)
+{
+  static const char *rcmap[] = { "nr", "+∞", "-∞", "0" };
+  int skip = lbl ? strlen(lbl) + 2 : 0;
+
+  printf(";; ");
+  if (lbl) printf("%s: ", lbl);
+  printf("   fpsr = 0x%08x\n", fp->fpsr);
+  printf(";;\t\tcond: %cn %cz %cc %cv %cqc\n",
+        (fp->fpsr >> 31)&1u ? '+' : '-',
+        (fp->fpsr >> 30)&1u ? '+' : '-',
+        (fp->fpsr >> 29)&1u ? '+' : '-',
+        (fp->fpsr >> 28)&1u ? '+' : '-',
+        (fp->fpsr >> 27)&1u ? '+' : '-');
+  printf(";;\t\terror:  %cidc %cixc %cufc %cofc %cdzc %cioc\n",
+        (fp->fpsr >>  7)&1u ? '+' : '-',
+        (fp->fpsr >>  4)&1u ? '+' : '-',
+        (fp->fpsr >>  3)&1u ? '+' : '-',
+        (fp->fpsr >>  2)&1u ? '+' : '-',
+        (fp->fpsr >>  1)&1u ? '+' : '-',
+        (fp->fpsr >>  0)&1u ? '+' : '-');
+  printf(";; %*s   fpcr = 0x%08x\n", skip, "", fp->fpcr);
+  printf(";;\t\ttrap: %cide %cixe %cufe %cofe %cdze %cioe\n",
+        (fp->fpcr >> 15)&1u ? '+' : '-',
+        (fp->fpcr >> 12)&1u ? '+' : '-',
+        (fp->fpcr >> 11)&1u ? '+' : '-',
+        (fp->fpcr >> 10)&1u ? '+' : '-',
+        (fp->fpcr >>  9)&1u ? '+' : '-',
+        (fp->fpcr >>  8)&1u ? '+' : '-');
+  printf(";;\t\tcontrol: %cahp %cdn %cfz rm=%s str=%d len=%d\n",
+        (fp->fpcr >> 26)&1u ? '+' : '-',
+        (fp->fpcr >> 25)&1u ? '+' : '-',
+        (fp->fpcr >> 24)&1u ? '+' : '-',
+        rcmap[(fp->fpcr >> 22)&3u],
+        (fp->fpcr >> 20)&3u,
+        (fp->fpcr >> 16)&7u);
+}
+
+void regdump_gp(const struct regmap *map)
+{
+  unsigned i;
+
+  printf(";; General-purpose registers:\n");
+  for (i = 0; i < 32; i++)
+    regdump(map, 0,
+           REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_64 | REGSRC_GP | i);
+  regdump(map, 0, REGF_HEX | REGF_64 | REGSRC_GP | REGIX_PC);
+
+  printf(";; Flags:\n");
+  regdump(map, 0, REGSRC_GP | REGF_32 | REGIX_NZCV);
+}
+
+void regdump_fp(const struct regmap *map)
+{
+  unsigned i;
+
+  printf(";; Floating-point/SIMD registers:\n");
+  for (i = 0; i < 32; i++)
+    regdump(map, 0,
+           REGF_HEX | REGF_UNSGN | REGF_SGN | REGF_FLT | REGF_CHR |
+           REGF_64 | REGF_32 | REGF_16 | REGF_8 |
+           REGSRC_SIMD | i | (7 << REGF_WDSHIFT));
+
+  printf(";; Floating-point state:\n");
+  dump_fpflags(0, map->fp);
+}
+
+void regdump_simd(const struct regmap *map) { ; }
+
+#endif
+
+/*----- The main entry point ----------------------------------------------*/
+
+/* --- @regdump@ --- *
+ *
+ * Arguments:  @const void *base@ = pointer to base structure, corresponding
+ *                     to the @REGF_SRCMASK@ part of @f@
+ *             @const char *lbl@ = label to print
+ *             @uint32 f@ = format control word; see @REGF_...@
+ *
+ * Returns:    ---
+ *
+ * Use:                Dump a register value, or chunk of memory.
+ *
+ *             This function is not usually called directly; instead, use
+ *             the `reg' or `mem' assembler macros.
+ */
+
+void regdump(const void *base, const char *lbl, uint32 f)
+{
+  unsigned ix = (f&REGF_IXMASK) >> REGF_IXSHIFT;
+  unsigned wd = 1 << ((f&REGF_WDMASK) >> REGF_WDSHIFT);
+  unsigned fmt, ty;
+  uint32 fmtbit, tybit;
+  const void *p;
+  char regbuf[8]; const char *reg = regname(regbuf, f);
+  const struct regmap *map;
+  const struct fmttab *tab;
+  struct fmtinfo fi;
+  int firstp = 1;
+  int skip;
+  size_t n;
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+  union vreg vr;
+#endif
+
+  if (reg) {
+    n = strlen(reg);
+    if (n < 7) {
+      memmove(regbuf + 7 - n, reg, n + 1);
+      memset(regbuf, ' ', 7 - n);
+    }
+  }
+
+  switch (f&REGF_SRCMASK) {
+    case REGSRC_ABS:
+      p = base;
+      break;
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+    case REGSRC_GP:
+      map = (const struct regmap *)base;
+      if (ix == REGIX_FLAGS && !(f&REGF_FMTMASK))
+       { dump_flags(lbl, reg, map->gp->gp[REGIX_FLAGS]); return; }
+      p = &map->gp->gp[ix];
+      break;
+    case REGSRC_SEG:
+      map = (const struct regmap *)base;
+      assert(wd == 1); assert((f&REGF_TYMASK) == REGF_16);
+      p = &map->gp->seg[ix];
+      break;
+    case REGSRC_STMMX:
+      map = (const struct regmap *)base;
+      if (ix == REGIX_FPFLAGS)
+       { assert(!(f&REGF_FMTMASK)); dump_fpflags(lbl, map->fx); return; }
+      if (!((map->fx->ftw << ix)&128u)) {
+       printf(";; ");
+       if (lbl) printf("%s: ", lbl);
+       if (reg) printf("%s = ", reg);
+       printf("                         dead\n");
+       return;
+      }
+      p = &map->fx->stmmx[ix];
+      break;
+    case REGSRC_SIMD:
+      map = (const struct regmap *)base;
+      if (ix == REGIX_FPFLAGS)
+       { assert(!(f&REGF_FMTMASK)); dump_mxflags(lbl, map->fx); return; }
+      if (wd <= 128)
+       p = &map->fx->xmm[ix];
+      else {
+       vr.v128[0] = map->fx->xmm[ix];
+       vr.v128[1] = map->avx->ymmh[ix];
+       assert(wd == 256);
+       p = &vr;
+      }
+      break;
+#endif
+
+#if CPUFAM_ARMEL
+    case REGSRC_GP:
+      map = (const struct regmap *)base;
+      if (ix == REGIX_CPSR && !(f&REGF_FMTMASK))
+       { dump_flags(lbl, map->gp->r[REGIX_CPSR].u32); return; }
+      p = &map->gp->r[ix];
+      break;
+    case REGSRC_FP:
+    case REGSRC_SIMD:
+      map = (const struct regmap *)base;
+      if (ix == REGIX_FPSCR) {
+       assert(!(f&REGF_FMTMASK));
+       dump_fpflags(lbl, map->fp->fpscr);
+       return;
+      }
+      switch (regwd(f)) {
+       case 32: p = &map->fp->u.s[ix]; break;
+       case 64: p = &map->fp->u.d[ix]; break;
+       case 128: p = &map->fp->u.q[ix]; break;
+       default: assert(0);
+      }
+      break;
+#endif
+
+#if CPUFAM_ARM64
+    case REGSRC_GP:
+      map = (const struct regmap *)base;
+      if (ix == REGIX_NZCV && !(f&REGF_FMTMASK))
+       { dump_flags(lbl, map->gp->r[REGIX_NZCV].u64); return; }
+      p = &map->gp->r[ix];
+      break;
+    case REGSRC_FP:
+    case REGSRC_SIMD:
+      map = (const struct regmap *)base;
+      if (ix == REGIX_FPFLAGS)
+       { assert(!(f&REGF_FMTMASK)); dump_fpflags(lbl, map->fp); return; }
+      p = &map->fp->v[ix];
+      break;
+#endif
+
+    default:
+      assert(0);
+  }
+
+  skip = (lbl ? strlen(lbl) + 2 : 0) + (reg ? strlen(reg) : 0);
+  fi.f = 0; if (wd > 1) fi.f |= FMTF_VECTOR;
+
+  for (ty = (f&REGF_TYMASK) >> REGF_TYSHIFT,
+        tybit = 1 << REGF_TYSHIFT;
+       ty;
+       ty >>= 1, tybit <<= 1) {
+    if (!(ty&1u)) continue;
+
+    for (fmt = (f&REGF_FMTMASK) >> REGF_FMTSHIFT,
+          fmtbit = 1 << REGF_FMTSHIFT;
+        fmt;
+        fmt >>= 1, fmtbit <<= 1) {
+
+      if (!(fmt&1u)) continue;
+
+      for (tab = fmttab; tab->mask; tab++)
+       if (tab->mask == (fmtbit | tybit)) goto found;
+      continue;
+    found:
+
+      if (firstp) {
+       printf(";;");
+       if (lbl) printf(" %s:", lbl);
+       if (reg) printf(" %s =", reg);
+       firstp = 0;
+      } else if (wd > 1)
+       printf("\n;; %*s =", skip, "");
+      else
+       fputs(" =", stdout);
+
+      fi.p = p; fi.wd = 0;
+      while (fi.wd < wd) { putchar(' '); tab->fmt(&fi); }
+    }
+  }
+  putchar('\n');
+}
+
+/*----- Other random utilities --------------------------------------------*/
+
+/* --- @regdump_freshline@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Begin a fresh line of output.
+ */
+
+void regdump_freshline(void) { putchar('\n'); }
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/base/regdump.h b/base/regdump.h
new file mode 100644 (file)
index 0000000..bbbd5bd
--- /dev/null
@@ -0,0 +1,941 @@
+/* -*-c-*-
+ *
+ * Register dump and debugging support
+ *
+ * (c) 2019 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_REGDUMP_H
+#define CATACOMB_REGDUMP_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#ifndef ENABLE_ASM_DEBUG
+#  error "Assembler-level debug disabled by `configure' script."
+#endif
+
+#if __ASSEMBLER__
+#  include "asm-common.h"
+#else
+#  include <float.h>
+#  include <mLib/bits.h>
+#endif
+
+/*----- Random utilities --------------------------------------------------*/
+
+#define DO8(_)                                                         \
+   _(0)  _(1)  _(2)  _(3)  _(4)  _(5)  _(6)  _(7)
+#define DOHI8(_)                                                       \
+   _(8)  _(9) _(10) _(11) _(12) _(13) _(14) _(15)
+
+#define DO16(_) DO8(_) DOHI8(_)
+
+#define DO32(_)                                                                \
+  DO16(_)                                                              \
+  _(16) _(17) _(18) _(19) _(20) _(21) _(22) _(23)                      \
+  _(24) _(25) _(26) _(27) _(28) _(29) _(30) _(31)
+
+/*----- Common data structures --------------------------------------------*/
+
+#if !__ASSEMBLER__
+
+/* The following are good on our assembler targets. */
+typedef signed char int8;
+typedef short int16;
+typedef int int32;
+#if LONG_MAX >> 31 > 0x7fffffff
+  typedef long int64;
+#else
+  typedef long long int64;
+#endif
+typedef float float32;
+typedef double float64;
+typedef long double float80;
+
+#if CPUFAM_X86 || CPUFAM_ARMEL
+#  define PTR32 void *p;
+#  define PTR64
+#endif
+#if CPUFAM_AMD64 || CPUFAM_ARM64
+#  define PTR32
+#  define PTR64 void *p;
+#endif
+
+#define SIMD_COMMON(wd)                                                        \
+  uint8 u8[wd/8];                                                      \
+  int8 i8[wd/8];                                                       \
+  uint16 u16[wd/16];                                                   \
+  int16 i16[wd/16];                                                    \
+  uint32 u32[wd/32];                                                   \
+  int32 i32[wd/32];                                                    \
+  uint64 u64[wd/64];                                                   \
+  int64 i64[wd/64];                                                    \
+  float32 f32[wd/32];                                                  \
+  float64 f64[wd/64]
+
+union gp32 { uint32 u32; int32 i32; PTR32 };
+union gp64 { uint64 u64; int64 i64; PTR64 };
+
+#endif
+
+/*----- Format word layout ------------------------------------------------*/
+
+#define REGF_IXMASK    0x000000ff
+#define REGF_IXSHIFT            0
+/* The index into the vector indicated by `REGF_SRCMASK', if applicable. */
+
+#define REGF_FMTMASK   0x0000ff00
+#define REGF_FMTSHIFT           8
+#define REGF_HEX       0x00000100
+#define REGF_CHR       0x00000200
+#define REGF_FLT       0x00000400
+#define REGF_UNSGN     0x00000800
+#define REGF_SGN       0x00001000
+/* How to format the value(s) found. */
+
+#define REGF_TYMASK    0x00ff0000
+#define REGF_TYSHIFT           16
+#define REGF_80                0x00010000
+#define REGF_64                0x00020000
+#define REGF_32                0x00040000
+#define REGF_16                0x00080000
+#define REGF_8         0x00100000
+/* Size of the value(s) to dump. */
+
+#define REGF_SRCMASK   0x0f000000
+#define   REGSRC_ABS   0x01000000      /* absolute address */
+#define   REGSRC_GP    0x02000000      /* general-purpose register */
+#define   REGSRC_FP    0x03000000      /* floating-point register */
+#define   REGSRC_SIMD  0x04000000      /* SIMD vector register */
+#define   REGSRC_STMMX 0x05000000      /* x86-specific: x87/MMX register */
+#define   REGSRC_SEG   0x06000000      /* x86-specific: segment register */
+/* Where to find the values. */
+
+#define REGF_WDMASK    0xf0000000
+#define REGF_WDSHIFT           28
+/* If we're to print a scalar, this is zero; otherwise, log_2 of the vector
+ * register width, in bits.
+ */
+
+/*----- x86 and AMD64 -----------------------------------------------------*/
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+
+#define   REGIX_FLAGS   0
+#define          REGIX_IP       1
+#define   REGIX_ADDR    2
+#define   REGIX_AX      3
+#define   REGIX_BX      4
+#define   REGIX_CX      5
+#define   REGIX_DX      6
+#define   REGIX_SI      7
+#define   REGIX_DI      8
+#define   REGIX_BP      9
+#define   REGIX_SP     10
+#if CPUFAM_X86
+#  define REGIX_GPLIM  11
+#endif
+#if CPUFAM_AMD64
+#  define REGIX_R8     11
+#  define REGIX_R9     12
+#  define REGIX_R10    13
+#  define REGIX_R11    14
+#  define REGIX_R12    15
+#  define REGIX_R13    16
+#  define REGIX_R14    17
+#  define REGIX_R15    18
+#  define REGIX_GPLIM  19
+#endif
+
+#define REGIX_CS        0
+#define REGIX_DS        1
+#define REGIX_SS        2
+#define REGIX_ES        3
+#define REGIX_FS        4
+#define REGIX_GS        5
+#define REGIX_SEGLIM    6
+
+#define REGIX_FPFLAGS  255
+
+#if !__ASSEMBLER__
+
+#if CPUFAM_X86
+typedef union gp32 gpreg;
+#endif
+#if CPUFAM_AMD64
+typedef union gp64 gpreg;
+#endif
+
+struct gpsave {
+  gpreg gp[REGIX_GPLIM];
+  uint16 seg[REGIX_SEGLIM];
+};
+
+union stmmx {
+  SIMD_COMMON(64);
+#if FLT_RADIX == 2 && LDBL_MANT_DIG == 64
+  long double f80;
+#endif
+unsigned char _pad[16];
+};
+
+union xmm { SIMD_COMMON(128); };
+union ymm { SIMD_COMMON(256); };
+union vreg { union xmm v128[2]; union ymm v256; };
+
+struct fxsave {
+  unsigned short fcw;
+  unsigned short fsw;
+  unsigned char ftw;
+  unsigned char _res0;
+  unsigned short fop;
+#if CPUFAM_X86
+  unsigned int fpu_ip;
+  unsigned short fpu_cs;
+  unsigned short _res1;
+  unsigned int fpu_dp;
+  unsigned short fpu_ds;
+  unsigned short _res2;
+#endif
+#if CPUFAM_AMD64
+  unsigned long long fpu_ip;
+  unsigned long long fpu_dp;
+#endif
+  unsigned int mxcsr;
+  unsigned int mxcsr_mask;
+
+  union stmmx stmmx[8];
+
+#if CPUFAM_X86
+  union xmm xmm[8];
+  unsigned char _pad0[8*16];
+#endif
+#if CPUFAM_AMD64
+  union xmm xmm[16];
+#endif
+
+  unsigned char _pad1[96];
+};
+
+struct xsave_avx {
+#if CPUFAM_X86
+  union xmm ymmh[8];
+  unsigned char _pad0[8*16];
+#endif
+#if CPUFAM_AMD64
+  union xmm ymmh[16];
+#endif
+};
+
+struct regmap {
+  struct gpsave *gp;
+  struct fxsave *fx;
+  struct xsave_avx *avx;
+};
+
+#else
+
+       .extern regdump_gpsave
+       .extern regdump_xtsave
+       .extern regdump_xtrstr
+       .extern regdump_gprstr
+
+       regmap_gp = 0*WORDSZ
+       regmap_fx = 1*WORDSZ
+       regmap_avx = 2*WORDSZ
+       regmap_size = 3*WORDSZ
+
+#define REGDEF_GPX86_COMMON(rn, RN)                                    \
+       regsrc.e##rn = REGSRC_GP | REGIX_##RN;                          \
+       regty.e##rn = REGF_32;                                          \
+       regfmt.e##rn = REGF_HEX;                                        \
+       regsrc.r##rn = REGSRC_GP | REGIX_##RN;                          \
+       regty.r##rn = REGF_64;                                          \
+       regfmt.r##rn = REGF_HEX
+
+#define REGDEF_GPX86_ABCD(rn, RN)                                      \
+       regsrc.rn##hl = (4 << REGF_WDSHIFT) | REGSRC_GP | REGIX_##RN##X; \
+       regty.rn##hl = REGF_8;                                          \
+       regfmt.rn##hl = REGF_HEX;                                       \
+       regsrc.rn##l = REGSRC_GP | REGIX_##RN##X;                       \
+       regty.rn##l = REGF_8;                                           \
+       regfmt.rn##l = REGF_HEX;                                        \
+       regsrc.rn##x = REGSRC_GP | REGIX_##RN##X;                       \
+       regty.rn##x = REGF_16;                                          \
+       regfmt.rn##x = REGF_HEX;                                        \
+       REGDEF_GPX86_COMMON(rn##x, RN##X)
+REGDEF_GPX86_ABCD(a, A)
+REGDEF_GPX86_ABCD(b, B)
+REGDEF_GPX86_ABCD(c, C)
+REGDEF_GPX86_ABCD(d, D)
+
+       regsrc.eflags = REGSRC_GP | REGIX_FLAGS
+       regty.eflags = REGF_32
+       regfmt.eflags = 0
+
+#if CPUFAM_AMD64
+       regsrc.rflags = REGSRC_GP | REGIX_FLAGS
+       regty.rflags = REGF_64
+       regfmt.rflags = 0
+#endif
+
+#define REGDEF_GPX86_XP(rn, RN)                                                \
+       regsrc.rn##l = REGSRC_GP | REGIX_##RN;                          \
+       regty.rn##l = REGF_8;                                           \
+       regfmt.rn##l = REGF_HEX;                                        \
+       regsrc.rn = REGSRC_GP | REGIX_##RN;                             \
+       regty.rn = REGF_16;                                             \
+       regfmt.rn = REGF_HEX;                                           \
+       REGDEF_GPX86_COMMON(rn, RN)
+REGDEF_GPX86_XP(ip, IP)
+REGDEF_GPX86_XP(si, SI)
+REGDEF_GPX86_XP(di, DI)
+REGDEF_GPX86_XP(bp, BP)
+REGDEF_GPX86_XP(sp, SP)
+
+#if CPUFAM_AMD64
+#  define REGDEF_GPAMD64(i)                                            \
+       regsrc.r##i##b = REGSRC_GP | REGIX_R##i;                        \
+       regty.r##i##b = REGF_8;                                         \
+       regfmt.r##i##b = REGF_HEX;                                      \
+       regsrc.r##i##w = REGSRC_GP | REGIX_R##i;                        \
+       regty.r##i##w = REGF_16;                                        \
+       regfmt.r##i##w = REGF_HEX;                                      \
+       regsrc.r##i##d = REGSRC_GP | REGIX_R##i;                        \
+       regty.r##i##d = REGF_32;                                        \
+       regfmt.r##i##d = REGF_HEX;                                      \
+       regsrc.r##i = REGSRC_GP | REGIX_R##i;                           \
+       regty.r##i = REGF_64;                                           \
+       regfmt.r##i = REGF_HEX;
+  DOHI8(REGDEF_GPAMD64)
+#endif
+
+#define REGDEF_SEG(rn, RN)                                             \
+       regsrc.rn = REGSRC_SEG | REGIX_##RN;                            \
+       regty.rn = REGF_16;                                             \
+       regfmt.rn = REGF_HEX
+REGDEF_SEG(ss, SS)
+REGDEF_SEG(cs, CS)
+REGDEF_SEG(ds, DS)
+REGDEF_SEG(es, ES)
+REGDEF_SEG(fs, FS)
+REGDEF_SEG(gs, GS)
+
+#define REGDEF_STMMX(i)                                                        \
+       regsrc.st##i = REGSRC_STMMX | i;                                \
+       regty.st##i = REGF_80;                                          \
+       regfmt.st##i = REGF_FLT;                                        \
+       regsrc.mm##i = (6 << REGF_WDSHIFT) | REGSRC_STMMX | i;          \
+       regty.mm##i = REGF_16;                                          \
+       regfmt.mm##i = REGF_HEX;
+DO8(REGDEF_STMMX)
+
+#define REGDEF_SIMD(i)                                                 \
+       regsrc.xmm##i = (7 << REGF_WDSHIFT) | REGSRC_SIMD | i;          \
+       regty.xmm##i = REGF_32;                                         \
+       regfmt.xmm##i = REGF_HEX;                                       \
+       regsrc.ymm##i = (8 << REGF_WDSHIFT) | REGSRC_SIMD | i;          \
+       regty.ymm##i = REGF_32;                                         \
+       regfmt.ymm##i = REGF_HEX;
+DO8(REGDEF_SIMD)
+#if CPUFAM_AMD64
+  DOHI8(REGDEF_SIMD)
+#endif
+
+       REGDUMP_GPSIZE = REGIX_GPLIM*WORDSZ + REGIX_SEGLIM*2
+
+#  if CPUFAM_AMD64 && ABI_SYSV
+       REGDUMP_SPADJ = REGDUMP_GPSIZE + WORDSZ + 128
+#  else
+       REGDUMP_SPADJ = REGDUMP_GPSIZE + WORDSZ
+#  endif
+
+.macro _saveregs addr=nil
+       // Save the registers, leaving r/ebp pointing to the register map.
+
+       // Stash r/eax.  This is bletcherous: hope we don't get a signal in
+       // the next few instructions.
+       mov     [R_sp(r) - REGDUMP_SPADJ + (REGIX_AX - 1)*WORDSZ], R_a(r)
+
+  .ifnes "\addr", "nil"
+       // Collect the effective address for the following dump, leaving it
+       // in the `addr' slot of the dump.
+       lea     R_a(r), \addr
+       mov     [R_sp(r) - REGDUMP_SPADJ + (REGIX_ADDR - 1)*WORDSZ], R_a(r)
+  .endif
+
+       // Make space for the register save area.  On AMD64 with System/V
+       // ABI, also skip the red zone.  Use `lea' here to preserve the
+       // flags.
+       lea     R_sp(r), [R_sp(r) - REGDUMP_SPADJ]
+
+       // Save flags and general-purpose registers.  On 32-bit x86, we save
+       // ebx here and establish a GOT pointer here for the benefit of the
+       // PLT-indirect calls made later on.
+       pushf
+#  if CPUFAM_X86
+       mov     [esp + 4*REGIX_BX], ebx
+       ldgot
+#  endif
+       callext F(regdump_gpsave)
+
+       // Make space for the extended registers.
+       sub     R_sp(r), R_c(r)
+       callext F(regdump_xtsave)
+
+       // Prepare for calling back into C.  On 32-bit x86, leave space for
+       // the arguments and set up the GOT pointer; on AMD64 Windows, leave
+       // the `shadow space' for the called-function's arguments.  Also,
+       // forcibly align the stack pointer to a 16-byte boundary.
+#  if CPUFAM_X86
+       sub     esp, 16
+#  elif ABI_WIN
+       sub     rsp, 32
+#  endif
+       and     R_sp(r), ~15
+.endm
+
+.macro _rstrregs
+       // Restore registers.
+
+       // We assume r/ebp still points to the register map.
+       callext F(regdump_xtrstr)
+       mov     R_sp(r), R_bp(r)
+       callext F(regdump_gprstr)
+       popf
+       lea     R_sp(r), [R_sp(r) + REGDUMP_SPADJ]
+.endm
+
+.macro _regbase
+#  if CPUFAM_X86
+       mov     [esp + 0], ebp
+#  elif ABI_SYSV
+       mov     rdi, rbp
+#  elif ABI_WIN
+       mov     rcx, rbp
+#  endif
+.endm
+
+.macro _membase
+       mov     R_a(r), [R_bp(r) + regmap_gp]
+#  if CPUFAM_X86
+       mov     eax, [eax + REGIX_ADDR*WORDSZ]
+       mov     [esp + 0], eax
+#  elif ABI_SYSV
+       mov     rdi, [rax + REGIX_ADDR*WORDSZ]
+#  elif ABI_WIN
+       mov     rcx, [rax + REGIX_ADDR*WORDSZ]
+#  endif
+.endm
+
+.macro _reglbl msg
+  .ifeqs "\msg", ""
+#  if CPUFAM_X86
+       mov     dword ptr [esp + 4], 0
+#  elif ABI_SYSV
+       xor     esi, esi
+#  elif ABI_WIN
+       xor     edx, edx
+#  endif
+  .else
+#  if CPUFAM_X86
+       lea     eax, [INTADDR(.L$_reglbl$\@)]
+       mov     [esp + 4], eax
+#  elif ABI_SYSV
+       lea     rsi, [INTADDR(.L$_reglbl$\@)]
+#  elif ABI_WIN
+       lea     rdx, [INTADDR(.L$_reglbl$\@)]
+#  endif
+    _LIT
+.L$_reglbl$\@:
+       .asciz  "\msg"
+    _ENDLIT
+  .endif
+.endm
+
+.macro _regfmt arg
+#  if CPUFAM_X86
+       mov     dword ptr [esp + 8], \arg
+#  elif ABI_SYSV
+       mov     edx, \arg
+#  elif ABI_WIN
+       mov     r8d, \arg
+#  endif
+.endm
+
+#endif
+
+#endif
+
+/*----- ARM32 -------------------------------------------------------------*/
+
+#if CPUFAM_ARMEL
+
+#if !__ASSEMBLER__
+extern unsigned regdump__flags;
+#endif
+#define REGF_VFP 1u
+#define REGF_D32 2u
+
+#define REGIX_CPSR 16
+#define REGIX_ADDR 17
+#define REGIX_GPLIM 18
+
+#define REGIX_FPSCR 255
+
+#if !__ASSEMBLER__
+
+union neon64 { SIMD_COMMON(64); };
+union neon128 { SIMD_COMMON(128); };
+
+struct gpsave { union gp32 r[REGIX_GPLIM]; };
+
+struct fpsave {
+  unsigned fpscr;
+  unsigned _pad0;
+  union {
+    float32 s[32];
+    union neon64 d[32];
+    union neon128 q[16];
+  } u;
+};
+
+struct regmap {
+  struct gpsave *gp;
+  struct fpsave *fp;
+};
+
+#else
+
+       .extern regdump_gpsave
+       .extern regdump_xtsave
+       .extern regdump_xtrstr
+       .extern regdump_gprstr
+
+       regmap_gp = 0
+       regmap_fp = 4
+       regmap_size = 8
+
+#define REGDEF_GP(i)                                                   \
+       regsrc.r##i = REGSRC_GP | i;                                    \
+       regty.r##i = REGF_32;                                           \
+       regfmt.r##i = REGF_HEX;
+DO16(REGDEF_GP)
+
+       regsrc.cpsr = REGSRC_GP | REGIX_CPSR
+       regty.cpsr = REGF_32
+       regfmt.cpsr = 0
+
+#define REGDEF_NEONS(i)                                                        \
+       regsrc.s##i = REGSRC_FP | i;                                    \
+       regty.s##i = REGF_32;                                           \
+       regfmt.s##i = REGF_FLT;
+DO32(REGDEF_NEONS)
+
+#define REGDEF_NEOND(i)                                                        \
+       regsrc.d##i = (6 << REGF_WDSHIFT) | REGSRC_FP | i;              \
+       regty.d##i = REGF_32;                                           \
+       regfmt.d##i = REGF_HEX;
+DO32(REGDEF_NEOND)
+
+#define REGDEF_NEONQ(i)                                                        \
+       regsrc.q##i = (7 << REGF_WDSHIFT) | REGSRC_FP | i;              \
+       regty.q##i = REGF_32;                                           \
+       regfmt.q##i = REGF_HEX;
+DO16(REGDEF_NEONQ)
+
+       regsrc.fpscr = REGSRC_FP | REGIX_FPSCR
+       regty.fpscr = REGF_32
+       regfmt.fpscr = 0
+
+       REGDUMP_GPSIZE = 4*REGIX_GPLIM
+       REGDUMP_FPSIZE_D16 = 8 + 16*8
+       REGDUMP_FPSIZE_D32 = 8 + 32*8
+
+.macro _saveregs base=nil, off=#0
+       // Save the registers, leaving r4 pointing to the register map.
+
+       // Stash r14.  This is bletcherous: hope we don't get a signal in
+       // the next few instructions.
+       str     r14, [r13, #-REGDUMP_GPSIZE + 14*4]
+
+  .ifnes "\base,\off", "nil,#0"
+       // Collect the effective address for the following dump, leaving it
+       // in the `addr' slot of the dump.
+    .ifeqs "\base", "nil"
+       adrl    r14, \off
+    .else
+       add     r14, \base, \off
+    .endif
+       str     r14, [r13, #-REGDUMP_GPSIZE + 4*REGIX_ADDR]
+  .endif
+
+       // Make space for the register save area.
+       sub     r13, r13, #REGDUMP_GPSIZE
+
+       // Save flags and general-purpose registers.
+       str     r12, [r13, #4*12]
+       bl      regdump_gpsave
+
+       // Make space for the extended registers.
+       sub     r13, r13, r0
+       bl      regdump_xtsave
+
+       // Prepare for calling back into C.
+       ldgot
+       mov     r0, r13
+       bic     r0, r0, #15
+       mov     r13, r0
+.endm
+
+.macro _rstrregs
+       // Restore registers.
+
+       // We assume r4 still points to the register map.
+       bl      regdump_xtrstr
+       mov     r13, r4
+       bl      regdump_gprstr
+       ldr     r14, [r13, #14*4]
+       add     r13, r13, #REGDUMP_GPSIZE
+.endm
+
+.macro _regbase
+       mov     r0, r5
+.endm
+
+.macro _membase
+       mov     r0, r6
+.endm
+
+.macro _reglbl msg
+       adrl    r1, .L$_reglbl$\@
+    _LIT
+.L$_reglbl$\@:
+       .asciz  "\msg"
+       .balign 4
+    _ENDLIT
+.endm
+
+.macro _regfmt arg
+       movw    r2, #\arg&0xffff
+       movt    r2, #(\arg >> 16)&0xffff
+.endm
+
+#endif
+
+#endif
+
+/*----- ARM64 -------------------------------------------------------------*/
+
+#if CPUFAM_ARM64
+
+#define REGIX_NZCV 32
+#define REGIX_PC 33
+#define REGIX_ADDR 34
+#define REGIX_GPLIM 36
+
+#define REGIX_FPFLAGS 255
+
+#if !__ASSEMBLER__
+
+union v128 { SIMD_COMMON(128); };
+
+struct gpsave { union gp64 r[REGIX_GPLIM]; };
+
+struct fpsave {
+  unsigned fpsr, fpcr;
+  union v128 v[32];
+};
+
+struct regmap {
+  struct gpsave *gp;
+  struct fpsave *fp;
+};
+
+#else
+
+       .extern regdump_gpsave
+       .extern regdump_xtsave
+       .extern regdump_xtrstr
+       .extern regdump_gprstr
+
+       regmap_gp = 0
+       regmap_fp = 8
+       regmap_size = 16
+
+#define REGDEF_GP(i)                                                   \
+       regsrc.x##i = REGSRC_GP | i;                                    \
+       regty.x##i = REGF_64;                                           \
+       regfmt.x##i = REGF_HEX;                                         \
+       regsrc.w##i = REGSRC_GP | i;                                    \
+       regty.w##i = REGF_32;                                           \
+       regfmt.w##i = REGF_HEX;
+DO32(REGDEF_GP)
+
+       regsrc.sp = REGSRC_GP | 31
+       regty.sp = REGF_64
+       regfmt.sp = REGF_HEX
+
+       regsrc.pc = REGSRC_GP | REGIX_PC
+       regty.pc = REGF_64
+       regfmt.pc = REGF_HEX
+
+       regsrc.nzcv = REGSRC_GP | REGIX_NZCV
+       regty.nzcv = REGF_32
+       regfmt.nzcv = 0
+
+#define REGDEF_FP(i)                                                   \
+       regsrc.b##i = REGSRC_FP | i;                                    \
+       regty.b##i = REGF_8;                                            \
+       regfmt.b##i = REGF_HEX;                                         \
+       regsrc.h##i = REGSRC_FP | i;                                    \
+       regty.h##i = REGF_16;                                           \
+       regfmt.h##i = REGF_HEX;                                         \
+       regsrc.s##i = REGSRC_FP | i;                                    \
+       regty.s##i = REGF_32;                                           \
+       regfmt.s##i = REGF_FLT;                                         \
+       regsrc.d##i = REGSRC_FP | i;                                    \
+       regty.d##i = REGF_64;                                           \
+       regfmt.d##i = REGF_FLT;                                         \
+       regsrc.v##i = (7 << REGF_WDSHIFT) | REGSRC_FP | i;              \
+       regty.v##i = REGF_32;                                           \
+       regfmt.v##i = REGF_HEX;
+DO32(REGDEF_FP)
+
+       regsrc.fpflags = REGSRC_FP | REGIX_FPFLAGS
+       regty.fpflags = REGF_32
+       regfmt.fpflags = 0
+
+       REGDUMP_GPSIZE = 8*REGIX_GPLIM
+       REGDUMP_FPSIZE = 16 + 16 + 32*16
+
+.macro _saveregs base=nil, off=#0
+       // Save the registers, leaving x20 pointing to the register map.
+
+       // Stash x30.  This is bletcherous: hope we don't get a signal in
+       // the next few instructions.
+       str     x30, [sp, #-REGDUMP_GPSIZE + 30*8]
+
+  .ifnes "\base,\off", "nil,#0"
+       // Collect the effective address for the following dump, leaving it
+       // in the `addr' slot of the dump.
+    .ifeqs "\base", "nil"
+       adr     x30, \off
+    .else
+       add     x30, \base, \off
+    .endif
+       str     x30, [sp, #-REGDUMP_GPSIZE + 8*REGIX_ADDR]
+  .endif
+
+       // Make space for the register save area.
+       sub     sp, sp, #REGDUMP_GPSIZE
+
+       // Save flags and general-purpose registers.
+       stp     x16, x17, [sp, #8*16]
+       bl      regdump_gpsave
+
+       // Make space for the extended registers.
+       sub     sp, sp, x0
+       bl      regdump_xtsave
+.endm
+
+.macro _rstrregs
+       // Restore registers.
+
+       // We assume x21 still points to the register map.
+       bl      regdump_xtrstr
+       mov     sp, x20
+       bl      regdump_gprstr
+       ldr     x30, [sp, #30*8]
+       add     sp, sp, #REGDUMP_GPSIZE
+.endm
+
+.macro _regbase
+       mov     x0, x21
+.endm
+
+.macro _membase
+       mov     x0, x22
+.endm
+
+.macro _reglbl msg
+       adr     x1, .L$_reglbl$\@
+    _LIT
+.L$_reglbl$\@:
+       .asciz  "\msg"
+       .balign 4
+    _ENDLIT
+.endm
+
+.macro _regfmt arg
+       movz    w2, #\arg&0xffff
+       movk    w2, #(\arg >> 16)&0xffff, lsl #16
+.endm
+
+#endif
+
+#endif
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @regdump_init@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Performs one-time initialization for register dumping.  In
+ *             particular, this performs CPU feature detection on platforms
+ *             where that is a difficult task: without it, registers
+ *             corresponding to optional architectural features can be
+ *             neither printed nor preserved by the register-dump machinery.
+ */
+
+#if !__ASSEMBLER__
+extern void regdump_init(void);
+#endif
+
+/* --- @regdump@ --- *
+ *
+ * Arguments:  @const void *base@ = pointer to base structure, corresponding
+ *                     to the @REGF_SRCMASK@ part of @f@
+ *             @const char *lbl@ = label to print
+ *             @uint32 f@ = format control word; see @REGF_...@
+ *
+ * Returns:    ---
+ *
+ * Use:                Dump a register value, or chunk of memory.
+ *
+ *             This function is not usually called directly; instead, use
+ *             the `reg' or `mem' assembler macros.
+ */
+
+#if !__ASSEMBLER__
+extern void regdump(const void *base, const char *lbl, uint32 f);
+#else
+       .extern regdump
+#endif
+
+/* --- @regdump_gp@, @regdump_fp@, @regdump_simd@ --- *
+ *
+ * Arguments:  @const struct regmap *map@ = pointer to register map
+ *
+ * Returns:    ---
+ *
+ * Use:                Dump the general-purpose/floating-point/SIMD registers.
+ *
+ *             This function is not usually called directly; instead, use
+ *             the `regdump' assembler macro.
+ */
+
+#if !__ASSEMBLER__
+extern void regdump_gp(const struct regmap */*map*/);
+extern void regdump_fp(const struct regmap */*map*/);
+extern void regdump_simd(const struct regmap */*map*/);
+#else
+       .extern regdump_gp
+       .extern regdump_fp
+       .extern regdump_simd
+#endif
+
+/* --- @regdump_freshline@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Begin a fresh line of output.
+ */
+
+#if !__ASSEMBLER__
+extern void regdump_freshline(void);
+#else
+       .extern regdump_freshline
+#endif
+
+/*----- Main user interface macros ----------------------------------------*/
+
+#if __ASSEMBLER__
+
+.macro terpri
+       _saveregs
+       callext F(regdump_freshline)
+       _rstrregs
+.endm
+
+.macro reg     lbl, rn, fmt=0
+       _saveregs
+       _regbase
+       _reglbl "\lbl"
+       .L$reg.fmt$\@ = regsrc.\rn | \fmt | \
+                (((\fmt&REGF_TYMASK) == 0)&regty.\rn) | \
+                (((\fmt&REGF_FMTMASK) == 0)&regfmt.\rn)
+       _regfmt .L$reg.fmt$\@
+       callext F(regdump)
+       _rstrregs
+.endm
+
+.macro mem     lbl, addr, fmt=0
+       _saveregs \addr
+       _membase
+       _reglbl "\lbl"
+       .L$mem.fmt$\@ = REGSRC_ABS | \fmt | \
+                (((\fmt&REGF_TYMASK) == 0)&REGF_32) | \
+                (((\fmt&REGF_FMTMASK) == 0)&REGF_HEX)
+       _regfmt .L$mem.fmt$\@
+       callext F(regdump)
+       _rstrregs
+.endm
+
+.macro regdump gp=nil, fp=nil, simd=nil
+       _saveregs
+  .ifnes "\gp", "nil"
+       _regbase
+       callext F(regdump_gp)
+  .endif
+  .ifnes "\fp", "nil"
+       _regbase
+       callext F(regdump_fp)
+  .endif
+  .ifnes "\simd", "nil"
+       _regbase
+       callext F(regdump_simd)
+  .endif
+       _rstrregs
+.endm
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/base/rsvr.c b/base/rsvr.c
new file mode 100644 (file)
index 0000000..a468db7
--- /dev/null
@@ -0,0 +1,481 @@
+/* -*-c-*-
+ *
+ * Reservoir and buffer handling
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rsvr.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @rsvr_mkplan@ --- *
+ *
+ * Arguments:  @rsvr_plan *plan@ = pointer to plan to fill in
+ *             @const rsvr_policy *pol@ = reservoir policy to follow
+ *             @size_t used@ = amount of data in the reservoir
+ *             @size_t insz@ = amount of fresh input data arriving
+ *
+ * Returns:    ---
+ *
+ * Use:                Prepares a plan for feeding input data into a block-oriented
+ *             operation.
+ *
+ *             The caller's code for following the plan proceeds in four
+ *             parts.
+ *
+ *               1. Insert the first @plan->head@ input items into the
+ *                  reservoir; there will be sufficient space, and
+ *                  @plan->head@ will be at most @pol->blksz@.
+ *
+ *               2. Process the first @plan->from_rsvr@ items from the
+ *                  reservoir, shifting the remaining items forward;
+ *                  @plan->from_rsvr@ will be a multiple of @pol->blksz@.
+ *
+ *               3. Process the next @plan->from_input@ items directly from
+ *                  the input; @plan->from_input@ will be a multiple of
+ *                  @pol->blksz@.
+ *
+ *               4. Insert the remaining @plan->tail@ input items into the
+ *                  reservoir for next time.
+ */
+
+void rsvr_mkplan(rsvr_plan *plan, const rsvr_policy *pol,
+                size_t used, size_t insz)
+{
+  unsigned extra = !!(pol->f&RSVRF_FULL);
+  unsigned n, final;
+
+  if (insz < pol->rsvrsz - used + extra) {
+    /* Easy case: there's enough space in the reservoir for the whole input,
+     * so just accumulate it and we're done.
+     */
+
+    plan->head = insz;
+    plan->from_rsvr = plan->from_input = plan->tail = 0;
+  } else {
+    /* The hard case.  We're going to have to actually process something. */
+
+    /* Firstly, we top the reservoir up to the next block boundary. */
+    n = (pol->rsvrsz - used)%pol->blksz;
+    plan->head = n; used += n; insz -= n;
+
+    /* Next, figure out the final amount we'll leave in the reservoir.  This
+     * will be congruent to USED, modulo the block size, and within the last
+     * BLKSZ-wide interval permitted.  We must have enough material to get
+     * here, or we'd be in the other branch above.
+     */
+    final = pol->rsvrsz - pol->blksz + extra +
+      (insz + pol->blksz - extra)%pol->blksz;
+
+    /* If we don't have enough input to drain the reservoir completely, and
+     * then top it up to the necessary level, then take as much as we can
+     * from the reservoir; otherwise, drain completely and then use up the
+     * remaining input directly.
+     */
+    if (insz < final) {
+      /* We don't have enough input to drain the reservoir completely and
+       * then top it up to the necessary final level.  Take what we can.
+       */
+
+      plan->from_rsvr = used + insz - final;
+      plan->from_input = 0;
+      plan->tail = insz;
+    } else {
+      /* We have lots of input.  Drain the reservoir fully, process the bulk
+       * of the input buffer, and load the rest into the reservoir at the
+       * end.
+       */
+
+      plan->from_rsvr = used;
+      plan->from_input = insz - final;
+      plan->tail = final;
+    }
+  }
+}
+
+/* --- @rsvr_setup@ --- *
+ *
+ * Arguments:  @rsvr_state *st@ = pointer to state structure to fill in
+ *             @const rsvr_policy *pol@ = reservoir policy to follow
+ *             @void *rsvr@ = pointer to the actual reservoir
+ *             @unsigned *used@ = pointer to the reservoir level
+ *             @const void *in@ = pointer to the input data
+ *             @size_t insz@ = size of the input
+ *
+ * Returns:    ---
+ *
+ * Use:                Prepares for a simple operation.  This performs the initial
+ *             copy of input data into the reservoir, and prepares for the
+ *             next step.
+ *
+ *             After this, the calling code should usually proceed as
+ *             follows.
+ *
+ *               1. Call @RSVR_NEXT@ in a sequence of loops, with
+ *                  successively smaller values of @n@, to process waiting
+ *                  data from the reservoir.  Usually, each @n@ will be some
+ *                  multiple of the block size @pol->blksz@, and the final
+ *                  loop will have @n = pol->blksz@.
+ *
+ *               2. Call @rsvr_done@ to indicate that this has been done.
+ *
+ *               3. Call @RSVR_NEXT@ in a sequence of loops, as in step 1,
+ *                  to process the remaining data from the input buffer.
+ *
+ *               4. Call @rsvr_done@ to indicate that the job is complete.
+ */
+
+void rsvr_setup(rsvr_state *st, const rsvr_policy *pol,
+               void *rsvr, unsigned *used, const void *in, size_t insz)
+{
+  rsvr_mkplan(&st->plan, pol, *used, insz);
+  st->rsvr = rsvr; st->in = in; st->used = used;
+
+  if (st->plan.head) {
+    memcpy(rsvr + *st->used, st->in, st->plan.head);
+    *st->used += st->plan.head; st->in += st->plan.head;
+  }
+  st->src = RSVRSRC_RSVR; st->p = st->rsvr; st->sz = st->plan.from_rsvr;
+}
+
+/* --- @RSVR_NEXT@, @rsvr_next@ --- *
+ *
+ * Arguments:  @rsvr_state *st@ = pointer to the state structure
+ *             @size_t n@ = amount of input data required, in bytes; should
+ *                     usually be a multiple of @pol->blksz@
+ *
+ * Returns:    A pointer to the next @n@ bytes of input, or null if there is
+ *             insufficient data remaining.
+ */
+
+const void *rsvr_next(rsvr_state *st, size_t n) { return RSVR_NEXT(st, n); }
+
+/* --- @rsvr_done@ --- *
+ *
+ * Arguments:  @rsvr_state *st@ = pointer to the state structure
+ *
+ * Returns:    Zero after the first pass, nonzero after the second.
+ *
+ * Use:                Reports that the first or second stage (see @rsvr_setup@
+ *             above) of an operation has been completed.
+ *
+ *             If the first stage is complete, then this shifts stuff about
+ *             in the reservoir and prepares for the second stage; if the
+ *             second stage is complete, then it copies the remaining input
+ *             into the reservoir and marks the state as complete.
+ */
+
+int rsvr_done(rsvr_state *st)
+{
+  assert(!st->sz);
+  switch (st->src) {
+    case RSVRSRC_RSVR:
+      if (st->plan.from_rsvr) {
+       if (st->plan.from_rsvr < *st->used) {
+         memmove(st->rsvr, st->rsvr + st->plan.from_rsvr,
+                 *st->used - st->plan.from_rsvr);
+       }
+       *st->used -= st->plan.from_rsvr;
+      }
+      st->src = RSVRSRC_INPUT;
+      st->p = st->in; st->sz = st->plan.from_input;
+      return (0);
+    case RSVRSRC_INPUT:
+      if (st->plan.tail) {
+       memcpy(st->rsvr + *st->used, st->p, st->plan.tail);
+       *st->used += st->plan.tail;
+      }
+      st->src = RSVRSRC_DONE;
+      st->p = 0; st->sz = 0;
+      return (1);
+    default:
+      abort();
+  }
+}
+
+/*----- Testing -----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <mLib/alloc.h>
+#include <mLib/bits.h>
+#include <mLib/darray.h>
+#include <mLib/report.h>
+#include <mLib/testrig.h>
+
+struct rng {
+  uint32 x;
+};
+
+static void init_rng(struct rng *r)
+  { r->x = 0; }
+
+static void step_rng(struct rng *r)
+  { r->x = U32(0x0d83c207*r->x + 0x380fcfea); }
+
+DA_DECL(uint_v, unsigned);
+
+struct testinfo {
+  rsvr_policy pol;
+  uint_v chunksz;
+  uint_v blksz;
+  unsigned used;
+  size_t off;
+  int ok;
+};
+
+static void show_uint_v(const char *what, const uint_v *v)
+{
+  size_t i;
+
+  printf("\t%s:", what);
+  for (i = 0; i < DA_LEN(v); i++) printf("%s%u", i ? ", " : " ", DA(v)[i]);
+  printf("\n");
+}
+
+static void report_policy(const struct rsvr_policy *pol)
+{
+  printf("\tpolicy: flags = 0x%08x%s; blksz = %u; rsvrsz = %u\n",
+        pol->f, pol->f&RSVRF_FULL ? " full" : pol->f ? "" : " nil",
+        pol->blksz, pol->rsvrsz);
+}
+
+static void report_testinfo(const struct testinfo *info)
+{
+  report_policy(&info->pol);
+  show_uint_v("chunksz", &info->chunksz);
+  show_uint_v("blksz", &info->blksz);
+  printf("\treservoir level = %u\n", info->used);
+  printf("\toffset = %lu\n", (unsigned long)info->off);
+}
+
+static void check(struct rng *r, struct testinfo *info,
+                 const void *p, size_t sz)
+{
+  const octet *q = p;
+  unsigned x;
+
+  while (sz) {
+    x = U8(r->x);
+    if (info->ok && *q != x) {
+      printf("\n*** FAIL data mismatch (0x%02x /= 0x%02x)\n", *q, x);
+      report_testinfo(info);
+      info->ok = 0;
+    }
+    q++; sz--; info->off++;
+    step_rng(r);
+  }
+}
+
+static void parse_intlist(uint_v *v, const char *p)
+{
+  char *q;
+  unsigned long n;
+  int e = errno;
+
+  for (;;) {
+    while (isspace((unsigned char)*p)) p++;
+    if (!*p) break;
+    if (*p == ',') p++;
+    while (isspace((unsigned char)*p)) p++;
+    errno = 0; n = strtoul(p, &q, 0);
+    if (errno || (*q && *q != ',' && !isspace((unsigned char)*q)))
+      die(1, "invalid int list");
+    p = q; DA_PUSH(v, n);
+  }
+  errno = e;
+}
+
+int vrfy_plan(dstr *dv)
+{
+  rsvr_policy pol;
+  rsvr_plan want, calc;
+  unsigned used;
+  size_t insz;
+  int ok = 1;
+
+  pol.f = *(unsigned long *)dv[0].buf;
+  pol.blksz = *(unsigned long *)dv[1].buf;
+  pol.rsvrsz = *(unsigned long *)dv[2].buf;
+  used = *(unsigned long *)dv[3].buf;
+  insz = *(unsigned long *)dv[4].buf;
+  want.head = *(unsigned long *)dv[5].buf;
+  want.from_rsvr = *(unsigned long *)dv[6].buf;
+  want.from_input = *(unsigned long *)dv[7].buf;
+  want.tail = *(unsigned long *)dv[8].buf;
+
+  rsvr_mkplan(&calc, &pol, used, insz);
+
+  if (want.head != calc.head ||
+      want.from_rsvr != calc.from_rsvr ||
+      want.from_input != calc.from_input ||
+      want.tail != calc.tail) {
+    printf("\n*** FAIL plan doesn't match\n");
+    report_policy(&pol);
+    printf("\treservoir level = %u\n", used);
+    printf("\tinput size = %lu\n", (unsigned long)insz);
+#define SHOW(what, slot) do {                                          \
+  printf("\t" what " (calc) %lu %s %lu (want)\n",                      \
+        (unsigned long)calc.slot,                                      \
+        calc.slot == want.slot ? "=" : "/=",                           \
+        (unsigned long)want.slot);                                     \
+} while(0)
+    SHOW("head", head);
+    SHOW("from reservoir", from_rsvr);
+    SHOW("from input", from_input);
+    SHOW("tail", tail);
+#undef SHOW
+    ok = 0;
+  }
+
+  return (ok);
+}
+
+static int vrfy_copy(dstr *dv)
+{
+  struct testinfo info;
+  rsvr_state st;
+  struct rng ra, rb;
+  octet *buf = 0, *rsvr;
+  const void *p;
+  size_t i, j, bsz = 0;
+  unsigned n, used0, lb, ub, fin;
+
+  init_rng(&ra); init_rng(&rb);
+  info.pol.f = *(unsigned long *)dv[0].buf;
+  info.pol.blksz = *(unsigned long *)dv[1].buf;
+  info.pol.rsvrsz = *(unsigned long *)dv[2].buf;
+  info.ok = 1; info.used = 0; info.off = 0;
+  rsvr = xmalloc(info.pol.rsvrsz);
+  DA_CREATE(&info.chunksz); parse_intlist(&info.chunksz, dv[3].buf);
+  DA_CREATE(&info.blksz); parse_intlist(&info.blksz, dv[4].buf);
+  for (i = 0; i < DA_LEN(&info.chunksz); i++)
+    if (bsz < DA(&info.chunksz)[i]) bsz = DA(&info.chunksz)[i];
+  buf = xmalloc(bsz);
+  for (i = 0; i < DA_LEN(&info.chunksz); i++) {
+    n = DA(&info.chunksz)[i];
+    for (j = 0; j < n; j++) { buf[j] = U8(ra.x); step_rng(&ra); }
+    used0 = info.used;
+    rsvr_setup(&st, &info.pol, rsvr, &info.used, buf, n);
+    if (n != st.plan.head + st.plan.from_input + st.plan.tail) {
+      printf("\n*** FAIL input size crosscheck "
+            "(%u /= %u + %lu + %u = %lu)\n",
+            n,
+            st.plan.head, (unsigned long)st.plan.from_input, st.plan.tail,
+            (unsigned long)(st.plan.head +
+                            st.plan.from_input +
+                            st.plan.tail));
+      report_testinfo(&info);
+      info.ok = 0;
+    }
+    if (st.plan.from_rsvr%info.pol.blksz) {
+      printf("\n*** FAIL reservoir chunk %u misaligned\n",
+            st.plan.from_rsvr);
+      report_testinfo(&info);
+      info.ok = 0;
+    }
+    if (st.plan.from_input%info.pol.blksz) {
+      printf("\n*** FAIL direct chunk %lu misaligned\n",
+            (unsigned long)st.plan.from_input);
+      report_testinfo(&info);
+      info.ok = 0;
+    }
+    if (st.plan.head > info.pol.rsvrsz - used0) {
+      printf("\n*** FAIL top-up out of range (%u + %u = %u > %u)\n",
+            used0, st.plan.head, used0 + st.plan.head, info.pol.rsvrsz);
+      report_testinfo(&info);
+      info.ok = 0;
+    }
+    if (st.plan.from_rsvr > used0 + st.plan.head) {
+      printf("\n*** FAIL shift out of range (%u > %u + %u = %u)\n",
+            st.plan.from_rsvr,
+            used0, st.plan.head, used0 + st.plan.head);
+      report_testinfo(&info);
+      info.ok = 0;
+    }
+    if (st.plan.head != n) {
+      ub = info.pol.rsvrsz + !!(info.pol.f&RSVRF_FULL);
+      lb = ub - info.pol.blksz;
+      fin = used0 + st.plan.head - st.plan.from_rsvr + st.plan.tail;
+      if (lb > fin) {
+       printf("\n*** FAIL final level out of bounds "
+              "(%u > %u = %u + %u - %u + %u)\n",
+              lb, fin,
+              used0, st.plan.head, st.plan.from_rsvr, st.plan.tail);
+       report_testinfo(&info);
+       info.ok = 0;
+      }
+      if (fin >= ub) {
+       printf("\n*** FAIL final level out of bounds "
+              "(%u + %u - %u + %u = %u >= %u)\n",
+              used0, st.plan.head, st.plan.from_rsvr, st.plan.tail,
+              fin, ub);
+       report_testinfo(&info);
+       info.ok = 0;
+      }
+    }
+
+    if (!info.ok) break;
+    RSVR_DO(&st) {
+      for (j = 0; j < DA_LEN(&info.blksz); j++) {
+       n = DA(&info.blksz)[j];
+       while ((p = RSVR_NEXT(&st, n)) != 0) check(&rb, &info, p, n);
+      }
+    }
+  }
+
+  DA_DESTROY(&info.chunksz);
+  DA_DESTROY(&info.blksz);
+  xfree(rsvr); xfree(buf);
+  return (info.ok);
+}
+
+static const struct test_chunk tests[] = {
+  { "plan", vrfy_plan,
+    { &type_ulong, &type_ulong, &type_ulong, &type_ulong, &type_ulong,
+      &type_ulong, &type_ulong, &type_ulong, &type_ulong } },
+  { "copy", vrfy_copy,
+    { &type_ulong, &type_ulong, &type_ulong, &type_string, &type_string } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  test_run(argc, argv, tests, SRCDIR "/t/rsvr");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/base/rsvr.h b/base/rsvr.h
new file mode 100644 (file)
index 0000000..9fb9c0a
--- /dev/null
@@ -0,0 +1,195 @@
+/* -*-c-*-
+ *
+ * Reservoir and buffer handling
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_RSVR_H
+#define CATACOMB_RSVR_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct rsvr_policy {
+  unsigned f;                          /* Flags... */
+#define RSVRF_FULL 1u                  /*   Hold back a full reservoir */
+  unsigned blksz;                      /* Block size */
+  unsigned rsvrsz;                     /* Reservoir size; multiple of
+                                        * @blksz@ */
+} rsvr_policy;
+
+typedef struct rsvr_plan {
+  unsigned head;                       /* First, accumulate @head@ bytes
+                                        * into the reservoir */
+  unsigned from_rsvr;                  /* Next, process @from_rsvr@ bytes
+                                        * from the reservoir */
+  size_t from_input;                   /* Then, process @from_input@ bytes
+                                        * directly from the input */
+  unsigned tail;                       /* Finally, accumulate the remaining
+                                        * @tail@ bytes of input into the
+                                        * reservoir */
+} rsvr_plan;
+
+enum { RSVRSRC_RSVR, RSVRSRC_INPUT, RSVRSRC_DONE };
+
+typedef struct rsvr_state {
+  rsvr_plan plan;
+  unsigned *used;
+  unsigned char *rsvr;
+  const unsigned char *in, *p;
+  size_t sz;
+  unsigned src;
+} rsvr_state;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @rsvr_mkplan@ --- *
+ *
+ * Arguments:  @rsvr_plan *plan@ = pointer to plan to fill in
+ *             @const rsvr_policy *pol@ = reservoir policy to follow
+ *             @size_t used@ = amount of data in the reservoir
+ *             @size_t insz@ = amount of fresh input data arriving
+ *
+ * Returns:    ---
+ *
+ * Use:                Prepares a plan for feeding input data into a block-oriented
+ *             operation.
+ *
+ *             The caller's code for following the plan proceeds in four
+ *             parts.
+ *
+ *               1. Insert the first @plan->head@ input items into the
+ *                  reservoir; there will be sufficient space, and
+ *                  @plan->head@ will be at most @pol->blksz@.
+ *
+ *               2. Process the first @plan->from_rsvr@ items from the
+ *                  reservoir, shifting the remaining items forward;
+ *                  @plan->from_rsvr@ will be a multiple of @pol->blksz@.
+ *
+ *               3. Process the next @plan->from_input@ items directly from
+ *                  the input; @plan->from_input@ will be a multiple of
+ *                  @pol->blksz@.
+ *
+ *               4. Insert the remaining @plan->tail@ input items into the
+ *                  reservoir for next time.
+ */
+
+extern void rsvr_mkplan(rsvr_plan */*plan*/, const rsvr_policy */*pol*/,
+                       size_t /*used*/, size_t /*insz*/);
+
+/* --- @rsvr_setup@ --- *
+ *
+ * Arguments:  @rsvr_state *st@ = pointer to state structure to fill in
+ *             @const rsvr_policy *pol@ = reservoir policy to follow
+ *             @void *rsvr@ = pointer to the actual reservoir
+ *             @unsigned *used@ = pointer to the reservoir level
+ *             @const void *in@ = pointer to the input data
+ *             @size_t insz@ = size of the input
+ *
+ * Returns:    ---
+ *
+ * Use:                Prepares for a simple operation.  This performs the initial
+ *             copy of input data into the reservoir, and prepares for the
+ *             next step.
+ *
+ *             After this, the calling code should usually proceed as
+ *             follows.
+ *
+ *               1. Call @RSVR_NEXT@ in a sequence of loops, with
+ *                  successively smaller values of @n@, to process waiting
+ *                  data from the reservoir.  Usually, each @n@ will be some
+ *                  multiple of the block size @pol->blksz@, and the final
+ *                  loop will have @n = pol->blksz@.
+ *
+ *               2. Call @rsvr_done@ to indicate that this has been done.
+ *
+ *               3. Call @RSVR_NEXT@ in a sequence of loops, as in step 1,
+ *                  to process the remaining data from the input buffer.
+ *
+ *               4. Call @rsvr_done@ to indicate that the job is complete.
+ */
+
+extern void rsvr_setup(rsvr_state */*st*/, const rsvr_policy */*pol*/,
+                      void */*rsvr*/, unsigned */*used*/,
+                      const void */*in*/, size_t /*insz*/);
+
+/* --- @RSVR_NEXT@, @rsvr_next@ --- *
+ *
+ * Arguments:  @rsvr_state *st@ = pointer to the state structure
+ *             @size_t n@ = amount of input data required, in bytes; should
+ *                     usually be a multiple of @pol->blksz@
+ *
+ * Returns:    A pointer to the next @n@ bytes of input, or null if there is
+ *             insufficient data remaining.
+ */
+
+#define RSVR_NEXT(st, n)                                               \
+       ((n) > (st)->sz                                                 \
+               ? 0                                                     \
+               : ((st)->sz -= (n),                                     \
+                  (st)->p += (n),                                      \
+                  (const void *)((st)->p - (n))))
+extern const void *rsvr_next(rsvr_state */*st*/, size_t /*n*/);
+
+/* --- @rsvr_done@ --- *
+ *
+ * Arguments:  @rsvr_state *st@ = pointer to the state structure
+ *
+ * Returns:    Zero after the first pass, nonzero after the second.
+ *
+ * Use:                Reports that the first or second stage (see @rsvr_setup@
+ *             above) of an operation has been completed.
+ *
+ *             If the first stage is complete, then this shifts stuff about
+ *             in the reservoir and prepares for the second stage; if the
+ *             second stage is complete, then it copies the remaining input
+ *             into the reservoir and marks the state as complete.
+ */
+
+extern int rsvr_done(rsvr_state */*st*/);
+
+/* --- @RSVR_DO@ --- *
+ *
+ * Arguments:  @st@ = pointer to state structure
+ *
+ * Use:                Invoke as @RSVR_DO(st) stmt@: performs two passes of @stmt@
+ *             over the reservoir and input buffers respectively.
+ */
+
+#define RSVR_DO(st) switch (0) while (!rsvr_done(st)) case 0:
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/base/t/rsvr b/base/t/rsvr
new file mode 100644 (file)
index 0000000..188adb3
--- /dev/null
@@ -0,0 +1,26 @@
+### -*-conf-*-
+### Tests for reservoir management.
+
+plan {
+  ## F BLKSZ RSVRSZ    USED INSZ       HEAD FROM-RSVR FROM-INPUT TAIL
+  0 8 8                        0 0             0 0 0 0;
+  0 8 8                        0 1             1 0 0 0;
+  0 8 8                        7 1             1 8 0 0;
+  1 8 8                        7 1             1 0 0 0;
+  0 8 8                        0 16            0 0 16 0;
+  0 8 8                        1 15            7 8 8 0;
+  1 8 8                        1 15            7 8 0 8;
+  0 8 8                        1 16            7 8 8 1;
+  1 8 8                        1 16            7 8 8 1;
+
+  0 8 8                        0 1             1 0 0 0;
+  0 8 8                        1 4             4 0 0 0;
+  0 8 8                        5 7             3 8 0 4;
+  0 8 8                        4 31            4 8 24 3;
+  0 8 8                        3 5             5 8 0 0;
+}
+
+copy {
+  ## F BLKSZ RSVRSZ    CHUNKSZ,...     BLKSZ,...
+  0 8 8                        1,4,7,31,5      16,8;
+}
diff --git a/base/test-regdump-a64.S b/base/test-regdump-a64.S
new file mode 100644 (file)
index 0000000..f91331e
--- /dev/null
@@ -0,0 +1,27 @@
+#include "config.h"
+#include "asm-common.h"
+#include "regdump.h"
+
+       .text
+
+       .p2align 5
+vec:
+       .long   1, 2, 3, 4, 5, 6, 7, 8
+
+FUNC(main)
+
+       pushreg x29, x30
+       setfp
+  endprologue
+
+       bl      regdump_init
+
+       cmp     x0, x0
+       reg     "simd", v1
+
+       mov     w0, #0
+       dropfp
+       popreg  x29, x30
+       ret
+
+ENDFUNC
diff --git a/base/test-regdump-arm.S b/base/test-regdump-arm.S
new file mode 100644 (file)
index 0000000..a49b101
--- /dev/null
@@ -0,0 +1,33 @@
+#include "config.h"
+#include "asm-common.h"
+#include "regdump.h"
+
+       .text
+       .arch   armv7-a
+
+       .p2align 5
+vec:
+       .long   1, 2, 3, 4, 5, 6, 7, 8
+
+FUNC(main)
+
+       pushreg r11, r14
+       setfp
+  endprologue
+
+       bl      regdump_init
+
+       cmp     r0, r0
+       regdump gp=t
+       reg     "general purpose", r1
+       reg     "          flags", cpsr
+       reg     "           simd", q0, fmt=REGF_HEX | REGF_32 | REGF_16
+       reg     "          float", d0, fmt=REGF_FLT | REGF_64
+       reg     "          float", s0
+       reg     "   float status", fpscr
+
+       mov     r0, #0
+       dropfp
+       popreg  r11, pc
+
+ENDFUNC
diff --git a/base/test-regdump-x86ish.S b/base/test-regdump-x86ish.S
new file mode 100644 (file)
index 0000000..a8c8d43
--- /dev/null
@@ -0,0 +1,38 @@
+#include "config.h"
+#include "asm-common.h"
+#include "regdump.h"
+
+       .text
+
+       .p2align 5
+vec:
+       .long   1, 2, 3, 4, 5, 6, 7, 8
+
+FUNC(main)
+
+       pushreg R_bp(r)
+       setfp
+       and     R_sp(r), ~15
+  endprologue
+
+       fldz
+       fld1
+       fldpi
+       fldl2t
+       fldl2e
+       fldlg2
+       fldln2
+       //fld1
+
+       ldgot
+       movdqa  xmm2, [INTADDR(vec)]
+       //vmovdqa       ymm2, [INTADDR(vec)]
+
+       reg     "my fp", xmm2, REGF_FLT | REGF_64 | REGF_32
+
+       xor     eax, eax
+       dropfp
+       popreg  R_bp(r)
+       ret
+
+ENDFUNC
index 8ebda7b..5335a2e 100644 (file)
@@ -152,7 +152,7 @@ m4_define([catacomb_DEFINE_CPU_OR_ABI],
        ;;m4_define([catacomb_seen_$3/$$2], [t])])])
   catacomb_CPU_FAMILIES([_def])
   nil) ;;
-  *) AC_MSG_ERROR([BUG: unexpected $1 \`$1']) ;;
+  *) AC_MSG_ERROR([BUG: unexpected $1 \`$$1']) ;;
 esac])
 
 dnl Now that's out the way, we can explain what we're doing.
@@ -186,6 +186,26 @@ case $CPUFAM in
   *) AC_MSG_RESULT([$CPUFAM/$ABI]) ;;
 esac
 
+dnl Consider enabling support for assembler-level debugging toys.
+AC_ARG_ENABLE([asm-debug],
+  AS_HELP_STRING([--enable-asm-debug],
+    [enable assembler debugging features]),
+  [mdw_asm_debug=$enableval], [mdw_asm_debug=no])
+case $CPUFAM in nil) mdw_asm_debug=no ;; esac
+case $mdw_asm_debug in
+  no) ;;
+  *) AC_DEFINE([ENABLE_ASM_DEBUG], [1],
+       [Define to enable assembler-level debugging.]) ;;
+esac
+AM_CONDITIONAL([ASM_DEBUG], [test x$mdw_asm_debug != xno])
+
+dnl Check for leading underscores on C symbols.
+LT_SYS_SYMBOL_USCORE
+case $sys_symbol_underscore in
+  yes) AC_DEFINE([SYM_USCORE], [1],
+        [Define if C symbols are prefixed with an underscore.]) ;;
+esac
+
 dnl--------------------------------------------------------------------------
 dnl CPU-specific assembler features.
 
@@ -285,6 +305,9 @@ AC_CHECK_HEADERS([sys/auxv.h])
 AC_CHECK_HEADERS([linux/auxvec.h])
 AC_CHECK_FUNCS([getauxval])
 
+dnl Some equipment for measuring CPU performance.
+AC_CHECK_HEADERS([linux/perf_event.h])
+
 dnl Find the bit lengths of the obvious integer types.  This will be useful
 dnl when deciding on a representation for multiprecision integers.
 type_bits="" type_bits_sep=""
@@ -407,7 +430,7 @@ dnl Set the master libraries we need.
 AC_SUBST([CATACOMB_LIBS])
 
 dnl Necessary support libraries.
-PKG_CHECK_MODULES([mLib], [mLib >= 2.2.2.1])
+PKG_CHECK_MODULES([mLib], [mLib >= 2.3.0])
 AM_CFLAGS="$AM_CFLAGS $mLib_CFLAGS"
 
 dnl--------------------------------------------------------------------------
index 9b82e2a..772d218 100644 (file)
@@ -23,9 +23,25 @@ libcatacomb.so.2 catacomb2 #MINVER#
 ## dispatch
        cpu_feature_p@Base 2.2.3
        dispatch_debug@Base 2.2.3
+       (optional|arch=i386 amd64)dispatch_x86ish_cpuid@Base 2.5.0
+       (optional|arch=i386 amd64)dispatch_x86ish_xmmregisters_p@Base 2.5.0
+
+## regdump (available with `--enable-asm-debug')
+       (optional)regdump_init@Base 2.5.0
+       (optional)regdump@Base 2.5.0
+       (optional)regdump_freshline@Base 2.5.0
+       (optional)regdump_gp@Base 2.5.0
+       (optional)regdump_fp@Base 2.5.0
+       (optional)regdump_simd@Base 2.5.0
+       (optional)regdump_gprstr@Base 2.5.0
+       (optional)regdump_gpsave@Base 2.5.0
+       (optional)regdump_xtrstr@Base 2.5.0
+       (optional)regdump_xtsave@Base 2.5.0
+       (optional|arch=armel armhf)regdump__flags@Base 2.5.0
 
 ## keysz
        keysz@Base 2.1.0
+       keysz_pad@Base 2.5.0
        keysz_fromdl@Base 2.1.1
        keysz_fromec@Base 2.1.1
        keysz_fromif@Base 2.1.1
@@ -43,6 +59,12 @@ libcatacomb.so.2 catacomb2 #MINVER#
        l_free@Base 2.1.0
        l_purge@Base 2.1.0
 
+## rsvr
+       rsvr_setup@Base 2.5.0
+       rsvr_mkplan@Base 2.5.0
+       rsvr_next@Base 2.5.0
+       rsvr_done@Base 2.5.0
+
 ###--------------------------------------------------------------------------
 ### Mathematical infrastructure.
 
@@ -102,11 +124,17 @@ libcatacomb.so.2 catacomb2 #MINVER#
        mpx_kmul@Base 2.1.1
        mpx_ksqr@Base 2.1.1
        (optional|arch=i386)mpx_umul4_x86_sse2@Base 2.3.0
+       (optional|arch=i386)mpx_umul4_x86_avx@Base 2.3.0
        (optional|arch=amd64)mpx_umul4_amd64_sse2@Base 2.3.0
+       (optional|arch=amd64)mpx_umul4_amd64_avx@Base 2.3.0
        (optional|arch=i386)mpxmont_mul4_x86_sse2@Base 2.3.0
+       (optional|arch=i386)mpxmont_mul4_x86_avx@Base 2.3.0
        (optional|arch=amd64)mpxmont_mul4_amd64_sse2@Base 2.3.0
+       (optional|arch=amd64)mpxmont_mul4_amd64_avx@Base 2.3.0
        (optional|arch=i386)mpxmont_redc4_x86_sse2@Base 2.3.0
+       (optional|arch=i386)mpxmont_redc4_x86_avx@Base 2.3.0
        (optional|arch=amd64)mpxmont_redc4_amd64_sse2@Base 2.3.0
+       (optional|arch=amd64)mpxmont_redc4_amd64_avx@Base 2.3.0
 
 ## mparena
        mparena_create@Base 2.0.0
@@ -363,7 +391,8 @@ libcatacomb.so.2 catacomb2 #MINVER#
        pgen_filter@Base 2.1.1
        pgen_test@Base 2.1.1
        pgen_jump@Base 2.2.4
-       pgen_primep@Base 2.1.1
+       pgen_granfrob@Base 2.5.0
+       pgen_primep@Base 2.5.0
        pgen_gcdstep@Base 2.1.1
        pgen_simulstep@Base 2.1.1
        pgen_simultest@Base 2.1.1
@@ -392,8 +421,8 @@ libcatacomb.so.2 catacomb2 #MINVER#
        strongprime@Base 2.3.1
 
 ## limlee
-       limlee_step@Base 2.2.4
-       limlee@Base 2.2.4
+       limlee_step@Base 2.5.1+
+       limlee@Base 2.5.1+
 
 ## gfx
        gfx_acc@Base 2.0.0
@@ -483,10 +512,10 @@ libcatacomb.so.2 catacomb2 #MINVER#
        ec_dbl@Base 2.2.0
        ec_neg@Base 2.2.0
        ec_sub@Base 2.2.0
-       ec_imul@Base 2.2.0
-       ec_mul@Base 2.2.0
-       ec_immul@Base 2.2.0
-       ec_mmul@Base 2.2.0
+       ec_imul@Base 2.5.1+
+       ec_mul@Base 2.5.1+
+       ec_immul@Base 2.5.1+
+       ec_mmul@Base 2.5.1+
        ec_check@Base 2.2.0
        ec_destroycurve@Base 2.2.0
        ec_idfix@Base 2.2.0
@@ -608,7 +637,7 @@ libcatacomb.so.2 catacomb2 #MINVER#
 
 ## lcrand
        lcrand@Base 2.0.0
-       lcrand_create@Base 2.0.0
+       lcrand_create@Base 2.5.1+
        lcrand_range@Base 2.0.0
 
 ## rand
@@ -616,7 +645,8 @@ libcatacomb.so.2 catacomb2 #MINVER#
        rand_noisesrc@Base 2.2.3
        rand_seed@Base 2.2.3
        rand_quick@Base 2.2.3
-       rand_key@Base 2.2.3
+       (optional|arch=i386 amd64)rand_quick_x86ish_rdrand@Base 2.5.0
+       rand_key@Base 2.5.1+
        rand_add@Base 2.2.3
        rand_goodbits@Base 2.2.3
        rand_get@Base 2.2.3
@@ -669,6 +699,12 @@ libcatacomb.so.2 catacomb2 #MINVER#
        gcipher_byname@Base 2.1.1
        gciphertab@Base 2.1.1
 
+## gaead
+       gaead_byname@Base 2.5.0
+       gaead_encrypt@Base 2.5.0
+       gaead_decrypt@Base 2.5.0
+       gaeadtab@Base 2.5.0
+
 ## ghash
        ghash_byname@Base 2.1.1
        ghashtab@Base 2.1.1
@@ -677,6 +713,78 @@ libcatacomb.so.2 catacomb2 #MINVER#
        gmac_byname@Base 2.1.1
        gmactab@Base 2.1.1
 
+## ccm
+       ccm_check@Base 2.5.0
+       ccm_fmtctr@Base 2.5.0
+       ccm_fmthdr@Base 2.5.0
+
+## gcm
+       gcm_mktable@Base 2.5.0
+       gcm_ghashdone@Base 2.5.0
+       gcm_concat@Base 2.5.0
+       gcm_mulk_64b@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_64b_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_64b_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_64b_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_64b_arm64_pmull@Base 2.5.0
+       gcm_mulk_64l@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_64l_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_64l_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_64l_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_64l_arm64_pmull@Base 2.5.0
+       gcm_mulk_96b@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_96b_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_96b_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_96b_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_96b_arm64_pmull@Base 2.5.0
+       gcm_mulk_96l@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_96l_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_96l_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_96l_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_96l_arm64_pmull@Base 2.5.0
+       gcm_mulk_128b@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_128b_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_128b_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_128b_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_128b_arm64_pmull@Base 2.5.0
+       gcm_mulk_128l@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_128l_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_128l_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_128l_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_128l_arm64_pmull@Base 2.5.0
+       gcm_mulk_192b@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_192b_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_192b_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_192b_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_192b_arm64_pmull@Base 2.5.0
+       gcm_mulk_192l@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_192l_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_192l_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_192l_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_192l_arm64_pmull@Base 2.5.0
+       gcm_mulk_256b@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_256b_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_256b_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_256b_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_256b_arm64_pmull@Base 2.5.0
+       gcm_mulk_256l@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_256l_x86ish_pclmul@Base 2.5.0
+       (optional|arch=i386 amd64)gcm_mulk_256l_x86ish_pclmul_avx@Base 2.5.0
+       (optional|arch=armel armhf)gcm_mulk_256l_arm_crypto@Base 2.5.0
+       (optional|arch=arm64)gcm_mulk_256l_arm64_pmull@Base 2.5.0
+
+## latinpoly
+       latinpoly_noncesz@Base 2.5.0
+       latinpoly_tagsz@Base 2.5.0
+       latinpoly_aadhash_naclbox@Base 2.5.0
+       latinpoly_aadhash_poly1305@Base 2.5.0
+       latinpoly_aaddestroy@Base 2.5.0
+       latinpoly_tag@Base 2.5.0
+
+## ocb
+       ocb_ctz@Base 2.5.0
+       ocb_ctzl@Base 2.5.0
+
 ## blowfish
        blowfish_init@Base 2.0.0
        blowfish_keysz@Base 2.0.0
@@ -719,6 +827,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        blowfish_counterbdry@Base 2.0.0
        blowfish_counter@Base 2.0.0
        blowfish_counterrand@Base 2.0.0
+       blowfish_ccminit@Base 2.5.0
+       blowfish_ccmreinit@Base 2.5.0
+       blowfish_ccmnoncesz@Base 2.5.0
+       blowfish_ccmtagsz@Base 2.5.0
+       blowfish_ccmaadhash@Base 2.5.0
+       blowfish_ccmencrypt@Base 2.5.0
+       blowfish_ccmdecrypt@Base 2.5.0
+       blowfish_ccmencryptdone@Base 2.5.0
+       blowfish_ccmdecryptdone@Base 2.5.0
+       blowfish_ccm@Base 2.5.0
+       blowfish_eaxinit@Base 2.5.0
+       blowfish_eaxreinit@Base 2.5.0
+       blowfish_eaxsetkey@Base 2.5.0
+       blowfish_eaxnoncesz@Base 2.5.0
+       blowfish_eaxtagsz@Base 2.5.0
+       blowfish_eaxaadinit@Base 2.5.0
+       blowfish_eaxaadhash@Base 2.5.0
+       blowfish_eaxencrypt@Base 2.5.0
+       blowfish_eaxdecrypt@Base 2.5.0
+       blowfish_eaxencryptdone@Base 2.5.0
+       blowfish_eaxdecryptdone@Base 2.5.0
+       blowfish_eax@Base 2.5.0
+       blowfish_gcminit@Base 2.5.0
+       blowfish_gcmreinit@Base 2.5.0
+       blowfish_gcmsetkey@Base 2.5.0
+       blowfish_gcmnoncesz@Base 2.5.0
+       blowfish_gcmtagsz@Base 2.5.0
+       blowfish_gcmaadinit@Base 2.5.0
+       blowfish_gcmaadhash@Base 2.5.0
+       blowfish_gcmencrypt@Base 2.5.0
+       blowfish_gcmdecrypt@Base 2.5.0
+       blowfish_gcmencryptdone@Base 2.5.0
+       blowfish_gcmdecryptdone@Base 2.5.0
+       blowfish_gcm@Base 2.5.0
+       blowfish_ocb1init@Base 2.5.0
+       blowfish_ocb1reinit@Base 2.5.0
+       blowfish_ocb1setkey@Base 2.5.0
+       blowfish_ocb1policy@Base 2.5.0
+       blowfish_ocb1noncesz@Base 2.5.0
+       blowfish_ocb1tagsz@Base 2.5.0
+       blowfish_ocb1aadinit@Base 2.5.0
+       blowfish_ocb1aadhash@Base 2.5.0
+       blowfish_ocb1aadtag@Base 2.5.0
+       blowfish_ocb1encrypt@Base 2.5.0
+       blowfish_ocb1decrypt@Base 2.5.0
+       blowfish_ocb1encryptdone@Base 2.5.0
+       blowfish_ocb1decryptdone@Base 2.5.0
+       blowfish_ocb1@Base 2.5.0
+       blowfish_ocb3init@Base 2.5.0
+       blowfish_ocb3step@Base 2.5.0
+       blowfish_ocb3reinit@Base 2.5.0
+       blowfish_ocb3setkey@Base 2.5.0
+       blowfish_ocb3noncesz@Base 2.5.0
+       blowfish_ocb3aadinit@Base 2.5.0
+       blowfish_ocb3aadhash@Base 2.5.0
+       blowfish_ocb3encrypt@Base 2.5.0
+       blowfish_ocb3decrypt@Base 2.5.0
+       blowfish_ocb3encryptdone@Base 2.5.0
+       blowfish_ocb3decryptdone@Base 2.5.0
+       blowfish_ocb3tagsz@Base 2.5.0
+       blowfish_ocb3@Base 2.5.0
+       blowfish_omacmasks@Base 2.5.0
+       blowfish_omacpolicy@Base 2.5.0
+       blowfish_omacdone@Base 2.5.0
+       blowfish_cmacinit@Base 2.5.0
+       blowfish_cmacsetkey@Base 2.5.0
+       blowfish_cmachash@Base 2.5.0
+       blowfish_cmacdone@Base 2.5.0
+       blowfish_cmac@Base 2.5.0
+       blowfish_pmac1init@Base 2.5.0
+       blowfish_pmac1setkey@Base 2.5.0
+       blowfish_pmac1hash@Base 2.5.0
+       blowfish_pmac1done@Base 2.5.0
+       blowfish_pmac1@Base 2.5.0
 
 ## cast128
        cast128_init@Base 2.0.0
@@ -763,6 +945,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        cast128_counterbdry@Base 2.0.0
        cast128_counter@Base 2.0.0
        cast128_counterrand@Base 2.0.0
+       cast128_ccminit@Base 2.5.0
+       cast128_ccmreinit@Base 2.5.0
+       cast128_ccmnoncesz@Base 2.5.0
+       cast128_ccmtagsz@Base 2.5.0
+       cast128_ccmaadhash@Base 2.5.0
+       cast128_ccmencrypt@Base 2.5.0
+       cast128_ccmdecrypt@Base 2.5.0
+       cast128_ccmencryptdone@Base 2.5.0
+       cast128_ccmdecryptdone@Base 2.5.0
+       cast128_ccm@Base 2.5.0
+       cast128_eaxinit@Base 2.5.0
+       cast128_eaxreinit@Base 2.5.0
+       cast128_eaxsetkey@Base 2.5.0
+       cast128_eaxnoncesz@Base 2.5.0
+       cast128_eaxtagsz@Base 2.5.0
+       cast128_eaxaadinit@Base 2.5.0
+       cast128_eaxaadhash@Base 2.5.0
+       cast128_eaxencrypt@Base 2.5.0
+       cast128_eaxdecrypt@Base 2.5.0
+       cast128_eaxencryptdone@Base 2.5.0
+       cast128_eaxdecryptdone@Base 2.5.0
+       cast128_eax@Base 2.5.0
+       cast128_gcminit@Base 2.5.0
+       cast128_gcmreinit@Base 2.5.0
+       cast128_gcmsetkey@Base 2.5.0
+       cast128_gcmnoncesz@Base 2.5.0
+       cast128_gcmtagsz@Base 2.5.0
+       cast128_gcmaadinit@Base 2.5.0
+       cast128_gcmaadhash@Base 2.5.0
+       cast128_gcmencrypt@Base 2.5.0
+       cast128_gcmdecrypt@Base 2.5.0
+       cast128_gcmencryptdone@Base 2.5.0
+       cast128_gcmdecryptdone@Base 2.5.0
+       cast128_gcm@Base 2.5.0
+       cast128_ocb1init@Base 2.5.0
+       cast128_ocb1reinit@Base 2.5.0
+       cast128_ocb1setkey@Base 2.5.0
+       cast128_ocb1policy@Base 2.5.0
+       cast128_ocb1noncesz@Base 2.5.0
+       cast128_ocb1tagsz@Base 2.5.0
+       cast128_ocb1aadinit@Base 2.5.0
+       cast128_ocb1aadhash@Base 2.5.0
+       cast128_ocb1aadtag@Base 2.5.0
+       cast128_ocb1encrypt@Base 2.5.0
+       cast128_ocb1decrypt@Base 2.5.0
+       cast128_ocb1encryptdone@Base 2.5.0
+       cast128_ocb1decryptdone@Base 2.5.0
+       cast128_ocb1@Base 2.5.0
+       cast128_ocb3init@Base 2.5.0
+       cast128_ocb3step@Base 2.5.0
+       cast128_ocb3reinit@Base 2.5.0
+       cast128_ocb3setkey@Base 2.5.0
+       cast128_ocb3noncesz@Base 2.5.0
+       cast128_ocb3aadinit@Base 2.5.0
+       cast128_ocb3aadhash@Base 2.5.0
+       cast128_ocb3encrypt@Base 2.5.0
+       cast128_ocb3decrypt@Base 2.5.0
+       cast128_ocb3encryptdone@Base 2.5.0
+       cast128_ocb3decryptdone@Base 2.5.0
+       cast128_ocb3tagsz@Base 2.5.0
+       cast128_ocb3@Base 2.5.0
+       cast128_omacmasks@Base 2.5.0
+       cast128_omacpolicy@Base 2.5.0
+       cast128_omacdone@Base 2.5.0
+       cast128_cmacinit@Base 2.5.0
+       cast128_cmacsetkey@Base 2.5.0
+       cast128_cmachash@Base 2.5.0
+       cast128_cmacdone@Base 2.5.0
+       cast128_cmac@Base 2.5.0
+       cast128_pmac1init@Base 2.5.0
+       cast128_pmac1setkey@Base 2.5.0
+       cast128_pmac1hash@Base 2.5.0
+       cast128_pmac1done@Base 2.5.0
+       cast128_pmac1@Base 2.5.0
 
 ## cast256
        cast256_init@Base 2.0.0
@@ -805,6 +1061,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        cast256_counterbdry@Base 2.0.0
        cast256_counter@Base 2.0.0
        cast256_counterrand@Base 2.0.0
+       cast256_ccminit@Base 2.5.0
+       cast256_ccmreinit@Base 2.5.0
+       cast256_ccmnoncesz@Base 2.5.0
+       cast256_ccmtagsz@Base 2.5.0
+       cast256_ccmaadhash@Base 2.5.0
+       cast256_ccmencrypt@Base 2.5.0
+       cast256_ccmdecrypt@Base 2.5.0
+       cast256_ccmencryptdone@Base 2.5.0
+       cast256_ccmdecryptdone@Base 2.5.0
+       cast256_ccm@Base 2.5.0
+       cast256_eaxinit@Base 2.5.0
+       cast256_eaxreinit@Base 2.5.0
+       cast256_eaxsetkey@Base 2.5.0
+       cast256_eaxnoncesz@Base 2.5.0
+       cast256_eaxtagsz@Base 2.5.0
+       cast256_eaxaadinit@Base 2.5.0
+       cast256_eaxaadhash@Base 2.5.0
+       cast256_eaxencrypt@Base 2.5.0
+       cast256_eaxdecrypt@Base 2.5.0
+       cast256_eaxencryptdone@Base 2.5.0
+       cast256_eaxdecryptdone@Base 2.5.0
+       cast256_eax@Base 2.5.0
+       cast256_gcminit@Base 2.5.0
+       cast256_gcmreinit@Base 2.5.0
+       cast256_gcmsetkey@Base 2.5.0
+       cast256_gcmnoncesz@Base 2.5.0
+       cast256_gcmtagsz@Base 2.5.0
+       cast256_gcmaadinit@Base 2.5.0
+       cast256_gcmaadhash@Base 2.5.0
+       cast256_gcmencrypt@Base 2.5.0
+       cast256_gcmdecrypt@Base 2.5.0
+       cast256_gcmencryptdone@Base 2.5.0
+       cast256_gcmdecryptdone@Base 2.5.0
+       cast256_gcm@Base 2.5.0
+       cast256_ocb1init@Base 2.5.0
+       cast256_ocb1reinit@Base 2.5.0
+       cast256_ocb1setkey@Base 2.5.0
+       cast256_ocb1policy@Base 2.5.0
+       cast256_ocb1noncesz@Base 2.5.0
+       cast256_ocb1tagsz@Base 2.5.0
+       cast256_ocb1aadinit@Base 2.5.0
+       cast256_ocb1aadhash@Base 2.5.0
+       cast256_ocb1aadtag@Base 2.5.0
+       cast256_ocb1encrypt@Base 2.5.0
+       cast256_ocb1decrypt@Base 2.5.0
+       cast256_ocb1encryptdone@Base 2.5.0
+       cast256_ocb1decryptdone@Base 2.5.0
+       cast256_ocb1@Base 2.5.0
+       cast256_ocb3init@Base 2.5.0
+       cast256_ocb3step@Base 2.5.0
+       cast256_ocb3reinit@Base 2.5.0
+       cast256_ocb3setkey@Base 2.5.0
+       cast256_ocb3noncesz@Base 2.5.0
+       cast256_ocb3aadinit@Base 2.5.0
+       cast256_ocb3aadhash@Base 2.5.0
+       cast256_ocb3encrypt@Base 2.5.0
+       cast256_ocb3decrypt@Base 2.5.0
+       cast256_ocb3encryptdone@Base 2.5.0
+       cast256_ocb3decryptdone@Base 2.5.0
+       cast256_ocb3tagsz@Base 2.5.0
+       cast256_ocb3@Base 2.5.0
+       cast256_omacmasks@Base 2.5.0
+       cast256_omacpolicy@Base 2.5.0
+       cast256_omacdone@Base 2.5.0
+       cast256_cmacinit@Base 2.5.0
+       cast256_cmacsetkey@Base 2.5.0
+       cast256_cmachash@Base 2.5.0
+       cast256_cmacdone@Base 2.5.0
+       cast256_cmac@Base 2.5.0
+       cast256_pmac1init@Base 2.5.0
+       cast256_pmac1setkey@Base 2.5.0
+       cast256_pmac1hash@Base 2.5.0
+       cast256_pmac1done@Base 2.5.0
+       cast256_pmac1@Base 2.5.0
 
 ## chacha
        chacha_init@Base 2.2.0
@@ -821,6 +1151,7 @@ libcatacomb.so.2 catacomb2 #MINVER#
        chacha12_encrypt@Base 2.2.0
        chacha20_encrypt@Base 2.2.0
        (optional|arch=i386 amd64)chacha_core_x86ish_sse2@Base 2.3.0
+       (optional|arch=i386 amd64)chacha_core_x86ish_avx@Base 2.3.0
        (optional|arch=armel armhf)chacha_core_arm_neon@Base 2.3.0
        (optional|arch=arm64)chacha_core_arm64@Base 2.4.3
        chacha8@Base 2.2.0
@@ -835,6 +1166,12 @@ libcatacomb.so.2 catacomb2 #MINVER#
        chacha8_ietf_rand@Base 2.4.2
        chacha12_ietf_rand@Base 2.4.2
        chacha20_ietf_rand@Base 2.4.2
+       chacha8_naclbox@Base 2.5.0
+       chacha12_naclbox@Base 2.5.0
+       chacha20_naclbox@Base 2.5.0
+       chacha8_poly1305@Base 2.5.0
+       chacha12_poly1305@Base 2.5.0
+       chacha20_poly1305@Base 2.5.0
        hchacha12_prf@Base 2.2.0
        hchacha20_prf@Base 2.2.0
        hchacha8_prf@Base 2.2.0
@@ -910,6 +1247,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        des_counterbdry@Base 2.0.0
        des_counter@Base 2.0.0
        des_counterrand@Base 2.0.0
+       des_ccminit@Base 2.5.0
+       des_ccmreinit@Base 2.5.0
+       des_ccmnoncesz@Base 2.5.0
+       des_ccmtagsz@Base 2.5.0
+       des_ccmaadhash@Base 2.5.0
+       des_ccmencrypt@Base 2.5.0
+       des_ccmdecrypt@Base 2.5.0
+       des_ccmencryptdone@Base 2.5.0
+       des_ccmdecryptdone@Base 2.5.0
+       des_ccm@Base 2.5.0
+       des_eaxinit@Base 2.5.0
+       des_eaxreinit@Base 2.5.0
+       des_eaxsetkey@Base 2.5.0
+       des_eaxnoncesz@Base 2.5.0
+       des_eaxtagsz@Base 2.5.0
+       des_eaxaadinit@Base 2.5.0
+       des_eaxaadhash@Base 2.5.0
+       des_eaxencrypt@Base 2.5.0
+       des_eaxdecrypt@Base 2.5.0
+       des_eaxencryptdone@Base 2.5.0
+       des_eaxdecryptdone@Base 2.5.0
+       des_eax@Base 2.5.0
+       des_gcminit@Base 2.5.0
+       des_gcmreinit@Base 2.5.0
+       des_gcmsetkey@Base 2.5.0
+       des_gcmnoncesz@Base 2.5.0
+       des_gcmtagsz@Base 2.5.0
+       des_gcmaadinit@Base 2.5.0
+       des_gcmaadhash@Base 2.5.0
+       des_gcmencrypt@Base 2.5.0
+       des_gcmdecrypt@Base 2.5.0
+       des_gcmencryptdone@Base 2.5.0
+       des_gcmdecryptdone@Base 2.5.0
+       des_gcm@Base 2.5.0
+       des_ocb1init@Base 2.5.0
+       des_ocb1reinit@Base 2.5.0
+       des_ocb1setkey@Base 2.5.0
+       des_ocb1policy@Base 2.5.0
+       des_ocb1noncesz@Base 2.5.0
+       des_ocb1tagsz@Base 2.5.0
+       des_ocb1aadinit@Base 2.5.0
+       des_ocb1aadhash@Base 2.5.0
+       des_ocb1aadtag@Base 2.5.0
+       des_ocb1encrypt@Base 2.5.0
+       des_ocb1decrypt@Base 2.5.0
+       des_ocb1encryptdone@Base 2.5.0
+       des_ocb1decryptdone@Base 2.5.0
+       des_ocb1@Base 2.5.0
+       des_ocb3init@Base 2.5.0
+       des_ocb3step@Base 2.5.0
+       des_ocb3reinit@Base 2.5.0
+       des_ocb3setkey@Base 2.5.0
+       des_ocb3noncesz@Base 2.5.0
+       des_ocb3aadinit@Base 2.5.0
+       des_ocb3aadhash@Base 2.5.0
+       des_ocb3encrypt@Base 2.5.0
+       des_ocb3decrypt@Base 2.5.0
+       des_ocb3encryptdone@Base 2.5.0
+       des_ocb3decryptdone@Base 2.5.0
+       des_ocb3tagsz@Base 2.5.0
+       des_ocb3@Base 2.5.0
+       des_omacmasks@Base 2.5.0
+       des_omacpolicy@Base 2.5.0
+       des_omacdone@Base 2.5.0
+       des_cmacinit@Base 2.5.0
+       des_cmacsetkey@Base 2.5.0
+       des_cmachash@Base 2.5.0
+       des_cmacdone@Base 2.5.0
+       des_cmac@Base 2.5.0
+       des_pmac1init@Base 2.5.0
+       des_pmac1setkey@Base 2.5.0
+       des_pmac1hash@Base 2.5.0
+       des_pmac1done@Base 2.5.0
+       des_pmac1@Base 2.5.0
 
 ## des3
        des3_init@Base 2.0.0
@@ -952,6 +1363,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        des3_counterbdry@Base 2.0.0
        des3_counter@Base 2.0.0
        des3_counterrand@Base 2.0.0
+       des3_ccminit@Base 2.5.0
+       des3_ccmreinit@Base 2.5.0
+       des3_ccmnoncesz@Base 2.5.0
+       des3_ccmtagsz@Base 2.5.0
+       des3_ccmaadhash@Base 2.5.0
+       des3_ccmencrypt@Base 2.5.0
+       des3_ccmdecrypt@Base 2.5.0
+       des3_ccmencryptdone@Base 2.5.0
+       des3_ccmdecryptdone@Base 2.5.0
+       des3_ccm@Base 2.5.0
+       des3_eaxinit@Base 2.5.0
+       des3_eaxreinit@Base 2.5.0
+       des3_eaxsetkey@Base 2.5.0
+       des3_eaxnoncesz@Base 2.5.0
+       des3_eaxtagsz@Base 2.5.0
+       des3_eaxaadinit@Base 2.5.0
+       des3_eaxaadhash@Base 2.5.0
+       des3_eaxencrypt@Base 2.5.0
+       des3_eaxdecrypt@Base 2.5.0
+       des3_eaxencryptdone@Base 2.5.0
+       des3_eaxdecryptdone@Base 2.5.0
+       des3_eax@Base 2.5.0
+       des3_gcminit@Base 2.5.0
+       des3_gcmreinit@Base 2.5.0
+       des3_gcmsetkey@Base 2.5.0
+       des3_gcmnoncesz@Base 2.5.0
+       des3_gcmtagsz@Base 2.5.0
+       des3_gcmaadinit@Base 2.5.0
+       des3_gcmaadhash@Base 2.5.0
+       des3_gcmencrypt@Base 2.5.0
+       des3_gcmdecrypt@Base 2.5.0
+       des3_gcmencryptdone@Base 2.5.0
+       des3_gcmdecryptdone@Base 2.5.0
+       des3_gcm@Base 2.5.0
+       des3_ocb1init@Base 2.5.0
+       des3_ocb1reinit@Base 2.5.0
+       des3_ocb1setkey@Base 2.5.0
+       des3_ocb1policy@Base 2.5.0
+       des3_ocb1noncesz@Base 2.5.0
+       des3_ocb1tagsz@Base 2.5.0
+       des3_ocb1aadinit@Base 2.5.0
+       des3_ocb1aadhash@Base 2.5.0
+       des3_ocb1aadtag@Base 2.5.0
+       des3_ocb1encrypt@Base 2.5.0
+       des3_ocb1decrypt@Base 2.5.0
+       des3_ocb1encryptdone@Base 2.5.0
+       des3_ocb1decryptdone@Base 2.5.0
+       des3_ocb1@Base 2.5.0
+       des3_ocb3init@Base 2.5.0
+       des3_ocb3step@Base 2.5.0
+       des3_ocb3reinit@Base 2.5.0
+       des3_ocb3setkey@Base 2.5.0
+       des3_ocb3noncesz@Base 2.5.0
+       des3_ocb3aadinit@Base 2.5.0
+       des3_ocb3aadhash@Base 2.5.0
+       des3_ocb3encrypt@Base 2.5.0
+       des3_ocb3decrypt@Base 2.5.0
+       des3_ocb3encryptdone@Base 2.5.0
+       des3_ocb3decryptdone@Base 2.5.0
+       des3_ocb3tagsz@Base 2.5.0
+       des3_ocb3@Base 2.5.0
+       des3_omacmasks@Base 2.5.0
+       des3_omacpolicy@Base 2.5.0
+       des3_omacdone@Base 2.5.0
+       des3_cmacinit@Base 2.5.0
+       des3_cmacsetkey@Base 2.5.0
+       des3_cmachash@Base 2.5.0
+       des3_cmacdone@Base 2.5.0
+       des3_cmac@Base 2.5.0
+       des3_pmac1init@Base 2.5.0
+       des3_pmac1setkey@Base 2.5.0
+       des3_pmac1hash@Base 2.5.0
+       des3_pmac1done@Base 2.5.0
+       des3_pmac1@Base 2.5.0
 
 ## desx
        desx_init@Base 2.0.0
@@ -994,6 +1479,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        desx_counterbdry@Base 2.0.0
        desx_counter@Base 2.0.0
        desx_counterrand@Base 2.0.0
+       desx_ccminit@Base 2.5.0
+       desx_ccmreinit@Base 2.5.0
+       desx_ccmnoncesz@Base 2.5.0
+       desx_ccmtagsz@Base 2.5.0
+       desx_ccmaadhash@Base 2.5.0
+       desx_ccmencrypt@Base 2.5.0
+       desx_ccmdecrypt@Base 2.5.0
+       desx_ccmencryptdone@Base 2.5.0
+       desx_ccmdecryptdone@Base 2.5.0
+       desx_ccm@Base 2.5.0
+       desx_eaxinit@Base 2.5.0
+       desx_eaxreinit@Base 2.5.0
+       desx_eaxsetkey@Base 2.5.0
+       desx_eaxnoncesz@Base 2.5.0
+       desx_eaxtagsz@Base 2.5.0
+       desx_eaxaadinit@Base 2.5.0
+       desx_eaxaadhash@Base 2.5.0
+       desx_eaxencrypt@Base 2.5.0
+       desx_eaxdecrypt@Base 2.5.0
+       desx_eaxencryptdone@Base 2.5.0
+       desx_eaxdecryptdone@Base 2.5.0
+       desx_eax@Base 2.5.0
+       desx_gcminit@Base 2.5.0
+       desx_gcmreinit@Base 2.5.0
+       desx_gcmsetkey@Base 2.5.0
+       desx_gcmnoncesz@Base 2.5.0
+       desx_gcmtagsz@Base 2.5.0
+       desx_gcmaadinit@Base 2.5.0
+       desx_gcmaadhash@Base 2.5.0
+       desx_gcmencrypt@Base 2.5.0
+       desx_gcmdecrypt@Base 2.5.0
+       desx_gcmencryptdone@Base 2.5.0
+       desx_gcmdecryptdone@Base 2.5.0
+       desx_gcm@Base 2.5.0
+       desx_ocb1init@Base 2.5.0
+       desx_ocb1reinit@Base 2.5.0
+       desx_ocb1setkey@Base 2.5.0
+       desx_ocb1policy@Base 2.5.0
+       desx_ocb1noncesz@Base 2.5.0
+       desx_ocb1tagsz@Base 2.5.0
+       desx_ocb1aadinit@Base 2.5.0
+       desx_ocb1aadhash@Base 2.5.0
+       desx_ocb1aadtag@Base 2.5.0
+       desx_ocb1encrypt@Base 2.5.0
+       desx_ocb1decrypt@Base 2.5.0
+       desx_ocb1encryptdone@Base 2.5.0
+       desx_ocb1decryptdone@Base 2.5.0
+       desx_ocb1@Base 2.5.0
+       desx_ocb3init@Base 2.5.0
+       desx_ocb3step@Base 2.5.0
+       desx_ocb3reinit@Base 2.5.0
+       desx_ocb3setkey@Base 2.5.0
+       desx_ocb3noncesz@Base 2.5.0
+       desx_ocb3aadinit@Base 2.5.0
+       desx_ocb3aadhash@Base 2.5.0
+       desx_ocb3encrypt@Base 2.5.0
+       desx_ocb3decrypt@Base 2.5.0
+       desx_ocb3encryptdone@Base 2.5.0
+       desx_ocb3decryptdone@Base 2.5.0
+       desx_ocb3tagsz@Base 2.5.0
+       desx_ocb3@Base 2.5.0
+       desx_omacmasks@Base 2.5.0
+       desx_omacpolicy@Base 2.5.0
+       desx_omacdone@Base 2.5.0
+       desx_cmacinit@Base 2.5.0
+       desx_cmacsetkey@Base 2.5.0
+       desx_cmachash@Base 2.5.0
+       desx_cmacdone@Base 2.5.0
+       desx_cmac@Base 2.5.0
+       desx_pmac1init@Base 2.5.0
+       desx_pmac1setkey@Base 2.5.0
+       desx_pmac1hash@Base 2.5.0
+       desx_pmac1done@Base 2.5.0
+       desx_pmac1@Base 2.5.0
 
 ## idea
        idea_init@Base 2.0.0
@@ -1036,6 +1595,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        idea_counterbdry@Base 2.0.0
        idea_counter@Base 2.4.3
        idea_counterrand@Base 2.0.0
+       idea_ccminit@Base 2.5.0
+       idea_ccmreinit@Base 2.5.0
+       idea_ccmnoncesz@Base 2.5.0
+       idea_ccmtagsz@Base 2.5.0
+       idea_ccmaadhash@Base 2.5.0
+       idea_ccmencrypt@Base 2.5.0
+       idea_ccmdecrypt@Base 2.5.0
+       idea_ccmencryptdone@Base 2.5.0
+       idea_ccmdecryptdone@Base 2.5.0
+       idea_ccm@Base 2.5.0
+       idea_eaxinit@Base 2.5.0
+       idea_eaxreinit@Base 2.5.0
+       idea_eaxsetkey@Base 2.5.0
+       idea_eaxnoncesz@Base 2.5.0
+       idea_eaxtagsz@Base 2.5.0
+       idea_eaxaadinit@Base 2.5.0
+       idea_eaxaadhash@Base 2.5.0
+       idea_eaxencrypt@Base 2.5.0
+       idea_eaxdecrypt@Base 2.5.0
+       idea_eaxencryptdone@Base 2.5.0
+       idea_eaxdecryptdone@Base 2.5.0
+       idea_eax@Base 2.5.0
+       idea_gcminit@Base 2.5.0
+       idea_gcmreinit@Base 2.5.0
+       idea_gcmsetkey@Base 2.5.0
+       idea_gcmnoncesz@Base 2.5.0
+       idea_gcmtagsz@Base 2.5.0
+       idea_gcmaadinit@Base 2.5.0
+       idea_gcmaadhash@Base 2.5.0
+       idea_gcmencrypt@Base 2.5.0
+       idea_gcmdecrypt@Base 2.5.0
+       idea_gcmencryptdone@Base 2.5.0
+       idea_gcmdecryptdone@Base 2.5.0
+       idea_gcm@Base 2.5.0
+       idea_ocb1init@Base 2.5.0
+       idea_ocb1reinit@Base 2.5.0
+       idea_ocb1setkey@Base 2.5.0
+       idea_ocb1policy@Base 2.5.0
+       idea_ocb1noncesz@Base 2.5.0
+       idea_ocb1tagsz@Base 2.5.0
+       idea_ocb1aadinit@Base 2.5.0
+       idea_ocb1aadhash@Base 2.5.0
+       idea_ocb1aadtag@Base 2.5.0
+       idea_ocb1encrypt@Base 2.5.0
+       idea_ocb1decrypt@Base 2.5.0
+       idea_ocb1encryptdone@Base 2.5.0
+       idea_ocb1decryptdone@Base 2.5.0
+       idea_ocb1@Base 2.5.0
+       idea_ocb3init@Base 2.5.0
+       idea_ocb3step@Base 2.5.0
+       idea_ocb3reinit@Base 2.5.0
+       idea_ocb3setkey@Base 2.5.0
+       idea_ocb3noncesz@Base 2.5.0
+       idea_ocb3aadinit@Base 2.5.0
+       idea_ocb3aadhash@Base 2.5.0
+       idea_ocb3encrypt@Base 2.5.0
+       idea_ocb3decrypt@Base 2.5.0
+       idea_ocb3encryptdone@Base 2.5.0
+       idea_ocb3decryptdone@Base 2.5.0
+       idea_ocb3tagsz@Base 2.5.0
+       idea_ocb3@Base 2.5.0
+       idea_omacmasks@Base 2.5.0
+       idea_omacpolicy@Base 2.5.0
+       idea_omacdone@Base 2.5.0
+       idea_cmacinit@Base 2.5.0
+       idea_cmacsetkey@Base 2.5.0
+       idea_cmachash@Base 2.5.0
+       idea_cmacdone@Base 2.5.0
+       idea_cmac@Base 2.5.0
+       idea_pmac1init@Base 2.5.0
+       idea_pmac1setkey@Base 2.5.0
+       idea_pmac1hash@Base 2.5.0
+       idea_pmac1done@Base 2.5.0
+       idea_pmac1@Base 2.5.0
 
 ## mars
        mars_init@Base 2.0.0
@@ -1079,6 +1712,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        mars_counterbdry@Base 2.0.0
        mars_counter@Base 2.0.0
        mars_counterrand@Base 2.0.0
+       mars_ccminit@Base 2.5.0
+       mars_ccmreinit@Base 2.5.0
+       mars_ccmnoncesz@Base 2.5.0
+       mars_ccmtagsz@Base 2.5.0
+       mars_ccmaadhash@Base 2.5.0
+       mars_ccmencrypt@Base 2.5.0
+       mars_ccmdecrypt@Base 2.5.0
+       mars_ccmencryptdone@Base 2.5.0
+       mars_ccmdecryptdone@Base 2.5.0
+       mars_ccm@Base 2.5.0
+       mars_eaxinit@Base 2.5.0
+       mars_eaxreinit@Base 2.5.0
+       mars_eaxsetkey@Base 2.5.0
+       mars_eaxnoncesz@Base 2.5.0
+       mars_eaxtagsz@Base 2.5.0
+       mars_eaxaadinit@Base 2.5.0
+       mars_eaxaadhash@Base 2.5.0
+       mars_eaxencrypt@Base 2.5.0
+       mars_eaxdecrypt@Base 2.5.0
+       mars_eaxencryptdone@Base 2.5.0
+       mars_eaxdecryptdone@Base 2.5.0
+       mars_eax@Base 2.5.0
+       mars_gcminit@Base 2.5.0
+       mars_gcmreinit@Base 2.5.0
+       mars_gcmsetkey@Base 2.5.0
+       mars_gcmnoncesz@Base 2.5.0
+       mars_gcmtagsz@Base 2.5.0
+       mars_gcmaadinit@Base 2.5.0
+       mars_gcmaadhash@Base 2.5.0
+       mars_gcmencrypt@Base 2.5.0
+       mars_gcmdecrypt@Base 2.5.0
+       mars_gcmencryptdone@Base 2.5.0
+       mars_gcmdecryptdone@Base 2.5.0
+       mars_gcm@Base 2.5.0
+       mars_ocb1init@Base 2.5.0
+       mars_ocb1reinit@Base 2.5.0
+       mars_ocb1setkey@Base 2.5.0
+       mars_ocb1policy@Base 2.5.0
+       mars_ocb1noncesz@Base 2.5.0
+       mars_ocb1tagsz@Base 2.5.0
+       mars_ocb1aadinit@Base 2.5.0
+       mars_ocb1aadhash@Base 2.5.0
+       mars_ocb1aadtag@Base 2.5.0
+       mars_ocb1encrypt@Base 2.5.0
+       mars_ocb1decrypt@Base 2.5.0
+       mars_ocb1encryptdone@Base 2.5.0
+       mars_ocb1decryptdone@Base 2.5.0
+       mars_ocb1@Base 2.5.0
+       mars_ocb3init@Base 2.5.0
+       mars_ocb3step@Base 2.5.0
+       mars_ocb3reinit@Base 2.5.0
+       mars_ocb3setkey@Base 2.5.0
+       mars_ocb3noncesz@Base 2.5.0
+       mars_ocb3aadinit@Base 2.5.0
+       mars_ocb3aadhash@Base 2.5.0
+       mars_ocb3encrypt@Base 2.5.0
+       mars_ocb3decrypt@Base 2.5.0
+       mars_ocb3encryptdone@Base 2.5.0
+       mars_ocb3decryptdone@Base 2.5.0
+       mars_ocb3tagsz@Base 2.5.0
+       mars_ocb3@Base 2.5.0
+       mars_omacmasks@Base 2.5.0
+       mars_omacpolicy@Base 2.5.0
+       mars_omacdone@Base 2.5.0
+       mars_cmacinit@Base 2.5.0
+       mars_cmacsetkey@Base 2.5.0
+       mars_cmachash@Base 2.5.0
+       mars_cmacdone@Base 2.5.0
+       mars_cmac@Base 2.5.0
+       mars_pmac1init@Base 2.5.0
+       mars_pmac1setkey@Base 2.5.0
+       mars_pmac1hash@Base 2.5.0
+       mars_pmac1done@Base 2.5.0
+       mars_pmac1@Base 2.5.0
 
 ## noekeon
        noekeon_init@Base 2.0.0
@@ -1121,6 +1828,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        noekeon_counterbdry@Base 2.0.0
        noekeon_counter@Base 2.0.0
        noekeon_counterrand@Base 2.0.0
+       noekeon_ccminit@Base 2.5.0
+       noekeon_ccmreinit@Base 2.5.0
+       noekeon_ccmnoncesz@Base 2.5.0
+       noekeon_ccmtagsz@Base 2.5.0
+       noekeon_ccmaadhash@Base 2.5.0
+       noekeon_ccmencrypt@Base 2.5.0
+       noekeon_ccmdecrypt@Base 2.5.0
+       noekeon_ccmencryptdone@Base 2.5.0
+       noekeon_ccmdecryptdone@Base 2.5.0
+       noekeon_ccm@Base 2.5.0
+       noekeon_eaxinit@Base 2.5.0
+       noekeon_eaxreinit@Base 2.5.0
+       noekeon_eaxsetkey@Base 2.5.0
+       noekeon_eaxnoncesz@Base 2.5.0
+       noekeon_eaxtagsz@Base 2.5.0
+       noekeon_eaxaadinit@Base 2.5.0
+       noekeon_eaxaadhash@Base 2.5.0
+       noekeon_eaxencrypt@Base 2.5.0
+       noekeon_eaxdecrypt@Base 2.5.0
+       noekeon_eaxencryptdone@Base 2.5.0
+       noekeon_eaxdecryptdone@Base 2.5.0
+       noekeon_eax@Base 2.5.0
+       noekeon_gcminit@Base 2.5.0
+       noekeon_gcmreinit@Base 2.5.0
+       noekeon_gcmsetkey@Base 2.5.0
+       noekeon_gcmnoncesz@Base 2.5.0
+       noekeon_gcmtagsz@Base 2.5.0
+       noekeon_gcmaadinit@Base 2.5.0
+       noekeon_gcmaadhash@Base 2.5.0
+       noekeon_gcmencrypt@Base 2.5.0
+       noekeon_gcmdecrypt@Base 2.5.0
+       noekeon_gcmencryptdone@Base 2.5.0
+       noekeon_gcmdecryptdone@Base 2.5.0
+       noekeon_gcm@Base 2.5.0
+       noekeon_ocb1init@Base 2.5.0
+       noekeon_ocb1reinit@Base 2.5.0
+       noekeon_ocb1setkey@Base 2.5.0
+       noekeon_ocb1policy@Base 2.5.0
+       noekeon_ocb1noncesz@Base 2.5.0
+       noekeon_ocb1tagsz@Base 2.5.0
+       noekeon_ocb1aadinit@Base 2.5.0
+       noekeon_ocb1aadhash@Base 2.5.0
+       noekeon_ocb1aadtag@Base 2.5.0
+       noekeon_ocb1encrypt@Base 2.5.0
+       noekeon_ocb1decrypt@Base 2.5.0
+       noekeon_ocb1encryptdone@Base 2.5.0
+       noekeon_ocb1decryptdone@Base 2.5.0
+       noekeon_ocb1@Base 2.5.0
+       noekeon_ocb3init@Base 2.5.0
+       noekeon_ocb3step@Base 2.5.0
+       noekeon_ocb3reinit@Base 2.5.0
+       noekeon_ocb3setkey@Base 2.5.0
+       noekeon_ocb3noncesz@Base 2.5.0
+       noekeon_ocb3aadinit@Base 2.5.0
+       noekeon_ocb3aadhash@Base 2.5.0
+       noekeon_ocb3encrypt@Base 2.5.0
+       noekeon_ocb3decrypt@Base 2.5.0
+       noekeon_ocb3encryptdone@Base 2.5.0
+       noekeon_ocb3decryptdone@Base 2.5.0
+       noekeon_ocb3tagsz@Base 2.5.0
+       noekeon_ocb3@Base 2.5.0
+       noekeon_omacmasks@Base 2.5.0
+       noekeon_omacpolicy@Base 2.5.0
+       noekeon_omacdone@Base 2.5.0
+       noekeon_cmacinit@Base 2.5.0
+       noekeon_cmacsetkey@Base 2.5.0
+       noekeon_cmachash@Base 2.5.0
+       noekeon_cmacdone@Base 2.5.0
+       noekeon_cmac@Base 2.5.0
+       noekeon_pmac1init@Base 2.5.0
+       noekeon_pmac1setkey@Base 2.5.0
+       noekeon_pmac1hash@Base 2.5.0
+       noekeon_pmac1done@Base 2.5.0
+       noekeon_pmac1@Base 2.5.0
 
 ## rc2
        rc2_init@Base 2.0.0
@@ -1165,6 +1946,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        rc2_counterbdry@Base 2.0.0
        rc2_counter@Base 2.0.0
        rc2_counterrand@Base 2.0.0
+       rc2_ccminit@Base 2.5.0
+       rc2_ccmreinit@Base 2.5.0
+       rc2_ccmnoncesz@Base 2.5.0
+       rc2_ccmtagsz@Base 2.5.0
+       rc2_ccmaadhash@Base 2.5.0
+       rc2_ccmencrypt@Base 2.5.0
+       rc2_ccmdecrypt@Base 2.5.0
+       rc2_ccmencryptdone@Base 2.5.0
+       rc2_ccmdecryptdone@Base 2.5.0
+       rc2_ccm@Base 2.5.0
+       rc2_eaxinit@Base 2.5.0
+       rc2_eaxreinit@Base 2.5.0
+       rc2_eaxsetkey@Base 2.5.0
+       rc2_eaxnoncesz@Base 2.5.0
+       rc2_eaxtagsz@Base 2.5.0
+       rc2_eaxaadinit@Base 2.5.0
+       rc2_eaxaadhash@Base 2.5.0
+       rc2_eaxencrypt@Base 2.5.0
+       rc2_eaxdecrypt@Base 2.5.0
+       rc2_eaxencryptdone@Base 2.5.0
+       rc2_eaxdecryptdone@Base 2.5.0
+       rc2_eax@Base 2.5.0
+       rc2_gcminit@Base 2.5.0
+       rc2_gcmreinit@Base 2.5.0
+       rc2_gcmsetkey@Base 2.5.0
+       rc2_gcmnoncesz@Base 2.5.0
+       rc2_gcmtagsz@Base 2.5.0
+       rc2_gcmaadinit@Base 2.5.0
+       rc2_gcmaadhash@Base 2.5.0
+       rc2_gcmencrypt@Base 2.5.0
+       rc2_gcmdecrypt@Base 2.5.0
+       rc2_gcmencryptdone@Base 2.5.0
+       rc2_gcmdecryptdone@Base 2.5.0
+       rc2_gcm@Base 2.5.0
+       rc2_ocb1init@Base 2.5.0
+       rc2_ocb1reinit@Base 2.5.0
+       rc2_ocb1setkey@Base 2.5.0
+       rc2_ocb1policy@Base 2.5.0
+       rc2_ocb1noncesz@Base 2.5.0
+       rc2_ocb1tagsz@Base 2.5.0
+       rc2_ocb1aadinit@Base 2.5.0
+       rc2_ocb1aadhash@Base 2.5.0
+       rc2_ocb1aadtag@Base 2.5.0
+       rc2_ocb1encrypt@Base 2.5.0
+       rc2_ocb1decrypt@Base 2.5.0
+       rc2_ocb1encryptdone@Base 2.5.0
+       rc2_ocb1decryptdone@Base 2.5.0
+       rc2_ocb1@Base 2.5.0
+       rc2_ocb3init@Base 2.5.0
+       rc2_ocb3step@Base 2.5.0
+       rc2_ocb3reinit@Base 2.5.0
+       rc2_ocb3setkey@Base 2.5.0
+       rc2_ocb3noncesz@Base 2.5.0
+       rc2_ocb3aadinit@Base 2.5.0
+       rc2_ocb3aadhash@Base 2.5.0
+       rc2_ocb3encrypt@Base 2.5.0
+       rc2_ocb3decrypt@Base 2.5.0
+       rc2_ocb3encryptdone@Base 2.5.0
+       rc2_ocb3decryptdone@Base 2.5.0
+       rc2_ocb3tagsz@Base 2.5.0
+       rc2_ocb3@Base 2.5.0
+       rc2_omacmasks@Base 2.5.0
+       rc2_omacpolicy@Base 2.5.0
+       rc2_omacdone@Base 2.5.0
+       rc2_cmacinit@Base 2.5.0
+       rc2_cmacsetkey@Base 2.5.0
+       rc2_cmachash@Base 2.5.0
+       rc2_cmacdone@Base 2.5.0
+       rc2_cmac@Base 2.5.0
+       rc2_pmac1init@Base 2.5.0
+       rc2_pmac1setkey@Base 2.5.0
+       rc2_pmac1hash@Base 2.5.0
+       rc2_pmac1done@Base 2.5.0
+       rc2_pmac1@Base 2.5.0
 
 ## rc4
        rc4_init@Base 2.0.0
@@ -1215,6 +2070,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        rc5_counterbdry@Base 2.0.0
        rc5_counter@Base 2.0.0
        rc5_counterrand@Base 2.0.0
+       rc5_ccminit@Base 2.5.0
+       rc5_ccmreinit@Base 2.5.0
+       rc5_ccmnoncesz@Base 2.5.0
+       rc5_ccmtagsz@Base 2.5.0
+       rc5_ccmaadhash@Base 2.5.0
+       rc5_ccmencrypt@Base 2.5.0
+       rc5_ccmdecrypt@Base 2.5.0
+       rc5_ccmencryptdone@Base 2.5.0
+       rc5_ccmdecryptdone@Base 2.5.0
+       rc5_ccm@Base 2.5.0
+       rc5_eaxinit@Base 2.5.0
+       rc5_eaxreinit@Base 2.5.0
+       rc5_eaxsetkey@Base 2.5.0
+       rc5_eaxnoncesz@Base 2.5.0
+       rc5_eaxtagsz@Base 2.5.0
+       rc5_eaxaadinit@Base 2.5.0
+       rc5_eaxaadhash@Base 2.5.0
+       rc5_eaxencrypt@Base 2.5.0
+       rc5_eaxdecrypt@Base 2.5.0
+       rc5_eaxencryptdone@Base 2.5.0
+       rc5_eaxdecryptdone@Base 2.5.0
+       rc5_eax@Base 2.5.0
+       rc5_gcminit@Base 2.5.0
+       rc5_gcmreinit@Base 2.5.0
+       rc5_gcmsetkey@Base 2.5.0
+       rc5_gcmnoncesz@Base 2.5.0
+       rc5_gcmtagsz@Base 2.5.0
+       rc5_gcmaadinit@Base 2.5.0
+       rc5_gcmaadhash@Base 2.5.0
+       rc5_gcmencrypt@Base 2.5.0
+       rc5_gcmdecrypt@Base 2.5.0
+       rc5_gcmencryptdone@Base 2.5.0
+       rc5_gcmdecryptdone@Base 2.5.0
+       rc5_gcm@Base 2.5.0
+       rc5_ocb1init@Base 2.5.0
+       rc5_ocb1reinit@Base 2.5.0
+       rc5_ocb1setkey@Base 2.5.0
+       rc5_ocb1policy@Base 2.5.0
+       rc5_ocb1noncesz@Base 2.5.0
+       rc5_ocb1tagsz@Base 2.5.0
+       rc5_ocb1aadinit@Base 2.5.0
+       rc5_ocb1aadhash@Base 2.5.0
+       rc5_ocb1aadtag@Base 2.5.0
+       rc5_ocb1encrypt@Base 2.5.0
+       rc5_ocb1decrypt@Base 2.5.0
+       rc5_ocb1encryptdone@Base 2.5.0
+       rc5_ocb1decryptdone@Base 2.5.0
+       rc5_ocb1@Base 2.5.0
+       rc5_ocb3init@Base 2.5.0
+       rc5_ocb3step@Base 2.5.0
+       rc5_ocb3reinit@Base 2.5.0
+       rc5_ocb3setkey@Base 2.5.0
+       rc5_ocb3noncesz@Base 2.5.0
+       rc5_ocb3aadinit@Base 2.5.0
+       rc5_ocb3aadhash@Base 2.5.0
+       rc5_ocb3encrypt@Base 2.5.0
+       rc5_ocb3decrypt@Base 2.5.0
+       rc5_ocb3encryptdone@Base 2.5.0
+       rc5_ocb3decryptdone@Base 2.5.0
+       rc5_ocb3tagsz@Base 2.5.0
+       rc5_ocb3@Base 2.5.0
+       rc5_omacmasks@Base 2.5.0
+       rc5_omacpolicy@Base 2.5.0
+       rc5_omacdone@Base 2.5.0
+       rc5_cmacinit@Base 2.5.0
+       rc5_cmacsetkey@Base 2.5.0
+       rc5_cmachash@Base 2.5.0
+       rc5_cmacdone@Base 2.5.0
+       rc5_cmac@Base 2.5.0
+       rc5_pmac1init@Base 2.5.0
+       rc5_pmac1setkey@Base 2.5.0
+       rc5_pmac1hash@Base 2.5.0
+       rc5_pmac1done@Base 2.5.0
+       rc5_pmac1@Base 2.5.0
 
 ## rijndael
        rijndael_init@Base 2.0.0
@@ -1229,12 +2158,15 @@ libcatacomb.so.2 catacomb2 #MINVER#
        (optional)rijndael_ti@Base 2.1.5
        (optional)rijndael_u@Base 2.1.5
        (optional|arch=i386 amd64)rijndael_setup_x86ish_aesni@Base 2.3.0
+       (optional|arch=i386 amd64)rijndael_setup_x86ish_aesni_avx@Base 2.3.0
        (optional|arch=armel armhf)rijndael_setup_arm_crypto@Base 2.2.5
        (optional|arch=arm64)rijndael_setup_arm64_crypto@Base 2.4.3
        (optional|arch=i386 amd64)rijndael_eblk_x86ish_aesni@Base 2.3.0
+       (optional|arch=i386 amd64)rijndael_eblk_x86ish_aesni_avx@Base 2.3.0
        (optional|arch=armel armhf)rijndael_eblk_arm_crypto@Base 2.2.5
        (optional|arch=arm64)rijndael_eblk_arm64_crypto@Base 2.4.3
        (optional|arch=i386 amd64)rijndael_dblk_x86ish_aesni@Base 2.3.0
+       (optional|arch=i386 amd64)rijndael_dblk_x86ish_aesni_avx@Base 2.3.0
        (optional|arch=armel armhf)rijndael_dblk_arm_crypto@Base 2.2.5
        (optional|arch=arm64)rijndael_dblk_arm64_crypto@Base 2.4.3
        rijndael_ecbinit@Base 2.1.1
@@ -1273,6 +2205,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        rijndael_counterbdry@Base 2.0.0
        rijndael_counter@Base 2.0.0
        rijndael_counterrand@Base 2.0.0
+       rijndael_ccminit@Base 2.5.0
+       rijndael_ccmreinit@Base 2.5.0
+       rijndael_ccmnoncesz@Base 2.5.0
+       rijndael_ccmtagsz@Base 2.5.0
+       rijndael_ccmaadhash@Base 2.5.0
+       rijndael_ccmencrypt@Base 2.5.0
+       rijndael_ccmdecrypt@Base 2.5.0
+       rijndael_ccmencryptdone@Base 2.5.0
+       rijndael_ccmdecryptdone@Base 2.5.0
+       rijndael_ccm@Base 2.5.0
+       rijndael_eaxinit@Base 2.5.0
+       rijndael_eaxreinit@Base 2.5.0
+       rijndael_eaxsetkey@Base 2.5.0
+       rijndael_eaxnoncesz@Base 2.5.0
+       rijndael_eaxtagsz@Base 2.5.0
+       rijndael_eaxaadinit@Base 2.5.0
+       rijndael_eaxaadhash@Base 2.5.0
+       rijndael_eaxencrypt@Base 2.5.0
+       rijndael_eaxdecrypt@Base 2.5.0
+       rijndael_eaxencryptdone@Base 2.5.0
+       rijndael_eaxdecryptdone@Base 2.5.0
+       rijndael_eax@Base 2.5.0
+       rijndael_gcminit@Base 2.5.0
+       rijndael_gcmreinit@Base 2.5.0
+       rijndael_gcmsetkey@Base 2.5.0
+       rijndael_gcmnoncesz@Base 2.5.0
+       rijndael_gcmtagsz@Base 2.5.0
+       rijndael_gcmaadinit@Base 2.5.0
+       rijndael_gcmaadhash@Base 2.5.0
+       rijndael_gcmencrypt@Base 2.5.0
+       rijndael_gcmdecrypt@Base 2.5.0
+       rijndael_gcmencryptdone@Base 2.5.0
+       rijndael_gcmdecryptdone@Base 2.5.0
+       rijndael_gcm@Base 2.5.0
+       rijndael_ocb1init@Base 2.5.0
+       rijndael_ocb1reinit@Base 2.5.0
+       rijndael_ocb1setkey@Base 2.5.0
+       rijndael_ocb1policy@Base 2.5.0
+       rijndael_ocb1noncesz@Base 2.5.0
+       rijndael_ocb1tagsz@Base 2.5.0
+       rijndael_ocb1aadinit@Base 2.5.0
+       rijndael_ocb1aadhash@Base 2.5.0
+       rijndael_ocb1aadtag@Base 2.5.0
+       rijndael_ocb1encrypt@Base 2.5.0
+       rijndael_ocb1decrypt@Base 2.5.0
+       rijndael_ocb1encryptdone@Base 2.5.0
+       rijndael_ocb1decryptdone@Base 2.5.0
+       rijndael_ocb1@Base 2.5.0
+       rijndael_ocb3init@Base 2.5.0
+       rijndael_ocb3step@Base 2.5.0
+       rijndael_ocb3reinit@Base 2.5.0
+       rijndael_ocb3setkey@Base 2.5.0
+       rijndael_ocb3noncesz@Base 2.5.0
+       rijndael_ocb3aadinit@Base 2.5.0
+       rijndael_ocb3aadhash@Base 2.5.0
+       rijndael_ocb3encrypt@Base 2.5.0
+       rijndael_ocb3decrypt@Base 2.5.0
+       rijndael_ocb3encryptdone@Base 2.5.0
+       rijndael_ocb3decryptdone@Base 2.5.0
+       rijndael_ocb3tagsz@Base 2.5.0
+       rijndael_ocb3@Base 2.5.0
+       rijndael_omacmasks@Base 2.5.0
+       rijndael_omacpolicy@Base 2.5.0
+       rijndael_omacdone@Base 2.5.0
+       rijndael_cmacinit@Base 2.5.0
+       rijndael_cmacsetkey@Base 2.5.0
+       rijndael_cmachash@Base 2.5.0
+       rijndael_cmacdone@Base 2.5.0
+       rijndael_cmac@Base 2.5.0
+       rijndael_pmac1init@Base 2.5.0
+       rijndael_pmac1setkey@Base 2.5.0
+       rijndael_pmac1hash@Base 2.5.0
+       rijndael_pmac1done@Base 2.5.0
+       rijndael_pmac1@Base 2.5.0
 
 ## rijndael192
        rijndael192_init@Base 2.0.0
@@ -1314,6 +2320,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        rijndael192_counterbdry@Base 2.0.0
        rijndael192_counter@Base 2.0.0
        rijndael192_counterrand@Base 2.0.0
+       rijndael192_ccminit@Base 2.5.0
+       rijndael192_ccmreinit@Base 2.5.0
+       rijndael192_ccmnoncesz@Base 2.5.0
+       rijndael192_ccmtagsz@Base 2.5.0
+       rijndael192_ccmaadhash@Base 2.5.0
+       rijndael192_ccmencrypt@Base 2.5.0
+       rijndael192_ccmdecrypt@Base 2.5.0
+       rijndael192_ccmencryptdone@Base 2.5.0
+       rijndael192_ccmdecryptdone@Base 2.5.0
+       rijndael192_ccm@Base 2.5.0
+       rijndael192_eaxinit@Base 2.5.0
+       rijndael192_eaxreinit@Base 2.5.0
+       rijndael192_eaxsetkey@Base 2.5.0
+       rijndael192_eaxnoncesz@Base 2.5.0
+       rijndael192_eaxtagsz@Base 2.5.0
+       rijndael192_eaxaadinit@Base 2.5.0
+       rijndael192_eaxaadhash@Base 2.5.0
+       rijndael192_eaxencrypt@Base 2.5.0
+       rijndael192_eaxdecrypt@Base 2.5.0
+       rijndael192_eaxencryptdone@Base 2.5.0
+       rijndael192_eaxdecryptdone@Base 2.5.0
+       rijndael192_eax@Base 2.5.0
+       rijndael192_gcminit@Base 2.5.0
+       rijndael192_gcmreinit@Base 2.5.0
+       rijndael192_gcmsetkey@Base 2.5.0
+       rijndael192_gcmnoncesz@Base 2.5.0
+       rijndael192_gcmtagsz@Base 2.5.0
+       rijndael192_gcmaadinit@Base 2.5.0
+       rijndael192_gcmaadhash@Base 2.5.0
+       rijndael192_gcmencrypt@Base 2.5.0
+       rijndael192_gcmdecrypt@Base 2.5.0
+       rijndael192_gcmencryptdone@Base 2.5.0
+       rijndael192_gcmdecryptdone@Base 2.5.0
+       rijndael192_gcm@Base 2.5.0
+       rijndael192_ocb1init@Base 2.5.0
+       rijndael192_ocb1reinit@Base 2.5.0
+       rijndael192_ocb1setkey@Base 2.5.0
+       rijndael192_ocb1policy@Base 2.5.0
+       rijndael192_ocb1noncesz@Base 2.5.0
+       rijndael192_ocb1tagsz@Base 2.5.0
+       rijndael192_ocb1aadinit@Base 2.5.0
+       rijndael192_ocb1aadhash@Base 2.5.0
+       rijndael192_ocb1aadtag@Base 2.5.0
+       rijndael192_ocb1encrypt@Base 2.5.0
+       rijndael192_ocb1decrypt@Base 2.5.0
+       rijndael192_ocb1encryptdone@Base 2.5.0
+       rijndael192_ocb1decryptdone@Base 2.5.0
+       rijndael192_ocb1@Base 2.5.0
+       rijndael192_ocb3init@Base 2.5.0
+       rijndael192_ocb3step@Base 2.5.0
+       rijndael192_ocb3reinit@Base 2.5.0
+       rijndael192_ocb3setkey@Base 2.5.0
+       rijndael192_ocb3noncesz@Base 2.5.0
+       rijndael192_ocb3aadinit@Base 2.5.0
+       rijndael192_ocb3aadhash@Base 2.5.0
+       rijndael192_ocb3encrypt@Base 2.5.0
+       rijndael192_ocb3decrypt@Base 2.5.0
+       rijndael192_ocb3encryptdone@Base 2.5.0
+       rijndael192_ocb3decryptdone@Base 2.5.0
+       rijndael192_ocb3tagsz@Base 2.5.0
+       rijndael192_ocb3@Base 2.5.0
+       rijndael192_omacmasks@Base 2.5.0
+       rijndael192_omacpolicy@Base 2.5.0
+       rijndael192_omacdone@Base 2.5.0
+       rijndael192_cmacinit@Base 2.5.0
+       rijndael192_cmacsetkey@Base 2.5.0
+       rijndael192_cmachash@Base 2.5.0
+       rijndael192_cmacdone@Base 2.5.0
+       rijndael192_cmac@Base 2.5.0
+       rijndael192_pmac1init@Base 2.5.0
+       rijndael192_pmac1setkey@Base 2.5.0
+       rijndael192_pmac1hash@Base 2.5.0
+       rijndael192_pmac1done@Base 2.5.0
+       rijndael192_pmac1@Base 2.5.0
 
 ## rijndael256
        rijndael256_init@Base 2.0.0
@@ -1355,6 +2435,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        rijndael256_counterbdry@Base 2.0.0
        rijndael256_counter@Base 2.0.0
        rijndael256_counterrand@Base 2.0.0
+       rijndael256_ccminit@Base 2.5.0
+       rijndael256_ccmreinit@Base 2.5.0
+       rijndael256_ccmnoncesz@Base 2.5.0
+       rijndael256_ccmtagsz@Base 2.5.0
+       rijndael256_ccmaadhash@Base 2.5.0
+       rijndael256_ccmencrypt@Base 2.5.0
+       rijndael256_ccmdecrypt@Base 2.5.0
+       rijndael256_ccmencryptdone@Base 2.5.0
+       rijndael256_ccmdecryptdone@Base 2.5.0
+       rijndael256_ccm@Base 2.5.0
+       rijndael256_eaxinit@Base 2.5.0
+       rijndael256_eaxreinit@Base 2.5.0
+       rijndael256_eaxsetkey@Base 2.5.0
+       rijndael256_eaxnoncesz@Base 2.5.0
+       rijndael256_eaxtagsz@Base 2.5.0
+       rijndael256_eaxaadinit@Base 2.5.0
+       rijndael256_eaxaadhash@Base 2.5.0
+       rijndael256_eaxencrypt@Base 2.5.0
+       rijndael256_eaxdecrypt@Base 2.5.0
+       rijndael256_eaxencryptdone@Base 2.5.0
+       rijndael256_eaxdecryptdone@Base 2.5.0
+       rijndael256_eax@Base 2.5.0
+       rijndael256_gcminit@Base 2.5.0
+       rijndael256_gcmreinit@Base 2.5.0
+       rijndael256_gcmsetkey@Base 2.5.0
+       rijndael256_gcmnoncesz@Base 2.5.0
+       rijndael256_gcmtagsz@Base 2.5.0
+       rijndael256_gcmaadinit@Base 2.5.0
+       rijndael256_gcmaadhash@Base 2.5.0
+       rijndael256_gcmencrypt@Base 2.5.0
+       rijndael256_gcmdecrypt@Base 2.5.0
+       rijndael256_gcmencryptdone@Base 2.5.0
+       rijndael256_gcmdecryptdone@Base 2.5.0
+       rijndael256_gcm@Base 2.5.0
+       rijndael256_ocb1init@Base 2.5.0
+       rijndael256_ocb1reinit@Base 2.5.0
+       rijndael256_ocb1setkey@Base 2.5.0
+       rijndael256_ocb1policy@Base 2.5.0
+       rijndael256_ocb1noncesz@Base 2.5.0
+       rijndael256_ocb1tagsz@Base 2.5.0
+       rijndael256_ocb1aadinit@Base 2.5.0
+       rijndael256_ocb1aadhash@Base 2.5.0
+       rijndael256_ocb1aadtag@Base 2.5.0
+       rijndael256_ocb1encrypt@Base 2.5.0
+       rijndael256_ocb1decrypt@Base 2.5.0
+       rijndael256_ocb1encryptdone@Base 2.5.0
+       rijndael256_ocb1decryptdone@Base 2.5.0
+       rijndael256_ocb1@Base 2.5.0
+       rijndael256_ocb3init@Base 2.5.0
+       rijndael256_ocb3step@Base 2.5.0
+       rijndael256_ocb3reinit@Base 2.5.0
+       rijndael256_ocb3setkey@Base 2.5.0
+       rijndael256_ocb3noncesz@Base 2.5.0
+       rijndael256_ocb3aadinit@Base 2.5.0
+       rijndael256_ocb3aadhash@Base 2.5.0
+       rijndael256_ocb3encrypt@Base 2.5.0
+       rijndael256_ocb3decrypt@Base 2.5.0
+       rijndael256_ocb3encryptdone@Base 2.5.0
+       rijndael256_ocb3decryptdone@Base 2.5.0
+       rijndael256_ocb3tagsz@Base 2.5.0
+       rijndael256_ocb3@Base 2.5.0
+       rijndael256_omacmasks@Base 2.5.0
+       rijndael256_omacpolicy@Base 2.5.0
+       rijndael256_omacdone@Base 2.5.0
+       rijndael256_cmacinit@Base 2.5.0
+       rijndael256_cmacsetkey@Base 2.5.0
+       rijndael256_cmachash@Base 2.5.0
+       rijndael256_cmacdone@Base 2.5.0
+       rijndael256_cmac@Base 2.5.0
+       rijndael256_pmac1init@Base 2.5.0
+       rijndael256_pmac1setkey@Base 2.5.0
+       rijndael256_pmac1hash@Base 2.5.0
+       rijndael256_pmac1done@Base 2.5.0
+       rijndael256_pmac1@Base 2.5.0
 
 ## safer
        safer_init@Base 2.0.0
@@ -1400,6 +2554,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        safer_counterbdry@Base 2.0.0
        safer_counter@Base 2.0.0
        safer_counterrand@Base 2.0.0
+       safer_ccminit@Base 2.5.0
+       safer_ccmreinit@Base 2.5.0
+       safer_ccmnoncesz@Base 2.5.0
+       safer_ccmtagsz@Base 2.5.0
+       safer_ccmaadhash@Base 2.5.0
+       safer_ccmencrypt@Base 2.5.0
+       safer_ccmdecrypt@Base 2.5.0
+       safer_ccmencryptdone@Base 2.5.0
+       safer_ccmdecryptdone@Base 2.5.0
+       safer_ccm@Base 2.5.0
+       safer_eaxinit@Base 2.5.0
+       safer_eaxreinit@Base 2.5.0
+       safer_eaxsetkey@Base 2.5.0
+       safer_eaxnoncesz@Base 2.5.0
+       safer_eaxtagsz@Base 2.5.0
+       safer_eaxaadinit@Base 2.5.0
+       safer_eaxaadhash@Base 2.5.0
+       safer_eaxencrypt@Base 2.5.0
+       safer_eaxdecrypt@Base 2.5.0
+       safer_eaxencryptdone@Base 2.5.0
+       safer_eaxdecryptdone@Base 2.5.0
+       safer_eax@Base 2.5.0
+       safer_gcminit@Base 2.5.0
+       safer_gcmreinit@Base 2.5.0
+       safer_gcmsetkey@Base 2.5.0
+       safer_gcmnoncesz@Base 2.5.0
+       safer_gcmtagsz@Base 2.5.0
+       safer_gcmaadinit@Base 2.5.0
+       safer_gcmaadhash@Base 2.5.0
+       safer_gcmencrypt@Base 2.5.0
+       safer_gcmdecrypt@Base 2.5.0
+       safer_gcmencryptdone@Base 2.5.0
+       safer_gcmdecryptdone@Base 2.5.0
+       safer_gcm@Base 2.5.0
+       safer_ocb1init@Base 2.5.0
+       safer_ocb1reinit@Base 2.5.0
+       safer_ocb1setkey@Base 2.5.0
+       safer_ocb1policy@Base 2.5.0
+       safer_ocb1noncesz@Base 2.5.0
+       safer_ocb1tagsz@Base 2.5.0
+       safer_ocb1aadinit@Base 2.5.0
+       safer_ocb1aadhash@Base 2.5.0
+       safer_ocb1aadtag@Base 2.5.0
+       safer_ocb1encrypt@Base 2.5.0
+       safer_ocb1decrypt@Base 2.5.0
+       safer_ocb1encryptdone@Base 2.5.0
+       safer_ocb1decryptdone@Base 2.5.0
+       safer_ocb1@Base 2.5.0
+       safer_ocb3init@Base 2.5.0
+       safer_ocb3step@Base 2.5.0
+       safer_ocb3reinit@Base 2.5.0
+       safer_ocb3setkey@Base 2.5.0
+       safer_ocb3noncesz@Base 2.5.0
+       safer_ocb3aadinit@Base 2.5.0
+       safer_ocb3aadhash@Base 2.5.0
+       safer_ocb3encrypt@Base 2.5.0
+       safer_ocb3decrypt@Base 2.5.0
+       safer_ocb3encryptdone@Base 2.5.0
+       safer_ocb3decryptdone@Base 2.5.0
+       safer_ocb3tagsz@Base 2.5.0
+       safer_ocb3@Base 2.5.0
+       safer_omacmasks@Base 2.5.0
+       safer_omacpolicy@Base 2.5.0
+       safer_omacdone@Base 2.5.0
+       safer_cmacinit@Base 2.5.0
+       safer_cmacsetkey@Base 2.5.0
+       safer_cmachash@Base 2.5.0
+       safer_cmacdone@Base 2.5.0
+       safer_cmac@Base 2.5.0
+       safer_pmac1init@Base 2.5.0
+       safer_pmac1setkey@Base 2.5.0
+       safer_pmac1hash@Base 2.5.0
+       safer_pmac1done@Base 2.5.0
+       safer_pmac1@Base 2.5.0
 
 ## safersk
        safersk_init@Base 2.0.0
@@ -1439,6 +2667,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        safersk_counterbdry@Base 2.0.0
        safersk_counter@Base 2.0.0
        safersk_counterrand@Base 2.0.0
+       safersk_ccminit@Base 2.5.0
+       safersk_ccmreinit@Base 2.5.0
+       safersk_ccmnoncesz@Base 2.5.0
+       safersk_ccmtagsz@Base 2.5.0
+       safersk_ccmaadhash@Base 2.5.0
+       safersk_ccmencrypt@Base 2.5.0
+       safersk_ccmdecrypt@Base 2.5.0
+       safersk_ccmencryptdone@Base 2.5.0
+       safersk_ccmdecryptdone@Base 2.5.0
+       safersk_ccm@Base 2.5.0
+       safersk_eaxinit@Base 2.5.0
+       safersk_eaxreinit@Base 2.5.0
+       safersk_eaxsetkey@Base 2.5.0
+       safersk_eaxnoncesz@Base 2.5.0
+       safersk_eaxtagsz@Base 2.5.0
+       safersk_eaxaadinit@Base 2.5.0
+       safersk_eaxaadhash@Base 2.5.0
+       safersk_eaxencrypt@Base 2.5.0
+       safersk_eaxdecrypt@Base 2.5.0
+       safersk_eaxencryptdone@Base 2.5.0
+       safersk_eaxdecryptdone@Base 2.5.0
+       safersk_eax@Base 2.5.0
+       safersk_gcminit@Base 2.5.0
+       safersk_gcmreinit@Base 2.5.0
+       safersk_gcmsetkey@Base 2.5.0
+       safersk_gcmnoncesz@Base 2.5.0
+       safersk_gcmtagsz@Base 2.5.0
+       safersk_gcmaadinit@Base 2.5.0
+       safersk_gcmaadhash@Base 2.5.0
+       safersk_gcmencrypt@Base 2.5.0
+       safersk_gcmdecrypt@Base 2.5.0
+       safersk_gcmencryptdone@Base 2.5.0
+       safersk_gcmdecryptdone@Base 2.5.0
+       safersk_gcm@Base 2.5.0
+       safersk_ocb1init@Base 2.5.0
+       safersk_ocb1reinit@Base 2.5.0
+       safersk_ocb1setkey@Base 2.5.0
+       safersk_ocb1policy@Base 2.5.0
+       safersk_ocb1noncesz@Base 2.5.0
+       safersk_ocb1tagsz@Base 2.5.0
+       safersk_ocb1aadinit@Base 2.5.0
+       safersk_ocb1aadhash@Base 2.5.0
+       safersk_ocb1aadtag@Base 2.5.0
+       safersk_ocb1encrypt@Base 2.5.0
+       safersk_ocb1decrypt@Base 2.5.0
+       safersk_ocb1encryptdone@Base 2.5.0
+       safersk_ocb1decryptdone@Base 2.5.0
+       safersk_ocb1@Base 2.5.0
+       safersk_ocb3init@Base 2.5.0
+       safersk_ocb3step@Base 2.5.0
+       safersk_ocb3reinit@Base 2.5.0
+       safersk_ocb3setkey@Base 2.5.0
+       safersk_ocb3noncesz@Base 2.5.0
+       safersk_ocb3aadinit@Base 2.5.0
+       safersk_ocb3aadhash@Base 2.5.0
+       safersk_ocb3encrypt@Base 2.5.0
+       safersk_ocb3decrypt@Base 2.5.0
+       safersk_ocb3encryptdone@Base 2.5.0
+       safersk_ocb3decryptdone@Base 2.5.0
+       safersk_ocb3tagsz@Base 2.5.0
+       safersk_ocb3@Base 2.5.0
+       safersk_omacmasks@Base 2.5.0
+       safersk_omacpolicy@Base 2.5.0
+       safersk_omacdone@Base 2.5.0
+       safersk_cmacinit@Base 2.5.0
+       safersk_cmacsetkey@Base 2.5.0
+       safersk_cmachash@Base 2.5.0
+       safersk_cmacdone@Base 2.5.0
+       safersk_cmac@Base 2.5.0
+       safersk_pmac1init@Base 2.5.0
+       safersk_pmac1setkey@Base 2.5.0
+       safersk_pmac1hash@Base 2.5.0
+       safersk_pmac1done@Base 2.5.0
+       safersk_pmac1@Base 2.5.0
 
 ## salsa20
        salsa20_init@Base 2.2.0
@@ -1455,6 +2757,7 @@ libcatacomb.so.2 catacomb2 #MINVER#
        salsa2012_encrypt@Base 2.2.0
        salsa20_encrypt@Base 2.2.0
        (optional|arch=i386 amd64)salsa20_core_x86ish_sse2@Base 2.2.3
+       (optional|arch=i386 amd64)salsa20_core_x86ish_avx@Base 2.2.3
        (optional|arch=armel armhf)salsa20_core_arm_neon@Base 2.2.3
        (optional|arch=arm64)salsa20_core_arm64@Base 2.4.3
        salsa208@Base 2.2.0
@@ -1469,6 +2772,12 @@ libcatacomb.so.2 catacomb2 #MINVER#
        salsa208_ietf_rand@Base 2.4.2
        salsa2012_ietf_rand@Base 2.4.2
        salsa20_ietf_rand@Base 2.4.2
+       salsa208_naclbox@Base 2.5.0
+       salsa2012_naclbox@Base 2.5.0
+       salsa20_naclbox@Base 2.5.0
+       salsa208_poly1305@Base 2.5.0
+       salsa2012_poly1305@Base 2.5.0
+       salsa20_poly1305@Base 2.5.0
        hsalsa208_prf@Base 2.2.0
        hsalsa2012_prf@Base 2.2.0
        hsalsa20_prf@Base 2.2.0
@@ -1549,6 +2858,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        serpent_counterbdry@Base 2.0.0
        serpent_counter@Base 2.0.0
        serpent_counterrand@Base 2.0.0
+       serpent_ccminit@Base 2.5.0
+       serpent_ccmreinit@Base 2.5.0
+       serpent_ccmnoncesz@Base 2.5.0
+       serpent_ccmtagsz@Base 2.5.0
+       serpent_ccmaadhash@Base 2.5.0
+       serpent_ccmencrypt@Base 2.5.0
+       serpent_ccmdecrypt@Base 2.5.0
+       serpent_ccmencryptdone@Base 2.5.0
+       serpent_ccmdecryptdone@Base 2.5.0
+       serpent_ccm@Base 2.5.0
+       serpent_eaxinit@Base 2.5.0
+       serpent_eaxreinit@Base 2.5.0
+       serpent_eaxsetkey@Base 2.5.0
+       serpent_eaxnoncesz@Base 2.5.0
+       serpent_eaxtagsz@Base 2.5.0
+       serpent_eaxaadinit@Base 2.5.0
+       serpent_eaxaadhash@Base 2.5.0
+       serpent_eaxencrypt@Base 2.5.0
+       serpent_eaxdecrypt@Base 2.5.0
+       serpent_eaxencryptdone@Base 2.5.0
+       serpent_eaxdecryptdone@Base 2.5.0
+       serpent_eax@Base 2.5.0
+       serpent_gcminit@Base 2.5.0
+       serpent_gcmreinit@Base 2.5.0
+       serpent_gcmsetkey@Base 2.5.0
+       serpent_gcmnoncesz@Base 2.5.0
+       serpent_gcmtagsz@Base 2.5.0
+       serpent_gcmaadinit@Base 2.5.0
+       serpent_gcmaadhash@Base 2.5.0
+       serpent_gcmencrypt@Base 2.5.0
+       serpent_gcmdecrypt@Base 2.5.0
+       serpent_gcmencryptdone@Base 2.5.0
+       serpent_gcmdecryptdone@Base 2.5.0
+       serpent_gcm@Base 2.5.0
+       serpent_ocb1init@Base 2.5.0
+       serpent_ocb1reinit@Base 2.5.0
+       serpent_ocb1setkey@Base 2.5.0
+       serpent_ocb1policy@Base 2.5.0
+       serpent_ocb1noncesz@Base 2.5.0
+       serpent_ocb1tagsz@Base 2.5.0
+       serpent_ocb1aadinit@Base 2.5.0
+       serpent_ocb1aadhash@Base 2.5.0
+       serpent_ocb1aadtag@Base 2.5.0
+       serpent_ocb1encrypt@Base 2.5.0
+       serpent_ocb1decrypt@Base 2.5.0
+       serpent_ocb1encryptdone@Base 2.5.0
+       serpent_ocb1decryptdone@Base 2.5.0
+       serpent_ocb1@Base 2.5.0
+       serpent_ocb3init@Base 2.5.0
+       serpent_ocb3step@Base 2.5.0
+       serpent_ocb3reinit@Base 2.5.0
+       serpent_ocb3setkey@Base 2.5.0
+       serpent_ocb3noncesz@Base 2.5.0
+       serpent_ocb3aadinit@Base 2.5.0
+       serpent_ocb3aadhash@Base 2.5.0
+       serpent_ocb3encrypt@Base 2.5.0
+       serpent_ocb3decrypt@Base 2.5.0
+       serpent_ocb3encryptdone@Base 2.5.0
+       serpent_ocb3decryptdone@Base 2.5.0
+       serpent_ocb3tagsz@Base 2.5.0
+       serpent_ocb3@Base 2.5.0
+       serpent_omacmasks@Base 2.5.0
+       serpent_omacpolicy@Base 2.5.0
+       serpent_omacdone@Base 2.5.0
+       serpent_cmacinit@Base 2.5.0
+       serpent_cmacsetkey@Base 2.5.0
+       serpent_cmachash@Base 2.5.0
+       serpent_cmacdone@Base 2.5.0
+       serpent_cmac@Base 2.5.0
+       serpent_pmac1init@Base 2.5.0
+       serpent_pmac1setkey@Base 2.5.0
+       serpent_pmac1hash@Base 2.5.0
+       serpent_pmac1done@Base 2.5.0
+       serpent_pmac1@Base 2.5.0
 
 ## skipjack
        skipjack_init@Base 2.0.0
@@ -1592,6 +2975,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        skipjack_counterbdry@Base 2.0.0
        skipjack_counter@Base 2.0.0
        skipjack_counterrand@Base 2.0.0
+       skipjack_ccminit@Base 2.5.0
+       skipjack_ccmreinit@Base 2.5.0
+       skipjack_ccmnoncesz@Base 2.5.0
+       skipjack_ccmtagsz@Base 2.5.0
+       skipjack_ccmaadhash@Base 2.5.0
+       skipjack_ccmencrypt@Base 2.5.0
+       skipjack_ccmdecrypt@Base 2.5.0
+       skipjack_ccmencryptdone@Base 2.5.0
+       skipjack_ccmdecryptdone@Base 2.5.0
+       skipjack_ccm@Base 2.5.0
+       skipjack_eaxinit@Base 2.5.0
+       skipjack_eaxreinit@Base 2.5.0
+       skipjack_eaxsetkey@Base 2.5.0
+       skipjack_eaxnoncesz@Base 2.5.0
+       skipjack_eaxtagsz@Base 2.5.0
+       skipjack_eaxaadinit@Base 2.5.0
+       skipjack_eaxaadhash@Base 2.5.0
+       skipjack_eaxencrypt@Base 2.5.0
+       skipjack_eaxdecrypt@Base 2.5.0
+       skipjack_eaxencryptdone@Base 2.5.0
+       skipjack_eaxdecryptdone@Base 2.5.0
+       skipjack_eax@Base 2.5.0
+       skipjack_gcminit@Base 2.5.0
+       skipjack_gcmreinit@Base 2.5.0
+       skipjack_gcmsetkey@Base 2.5.0
+       skipjack_gcmnoncesz@Base 2.5.0
+       skipjack_gcmtagsz@Base 2.5.0
+       skipjack_gcmaadinit@Base 2.5.0
+       skipjack_gcmaadhash@Base 2.5.0
+       skipjack_gcmencrypt@Base 2.5.0
+       skipjack_gcmdecrypt@Base 2.5.0
+       skipjack_gcmencryptdone@Base 2.5.0
+       skipjack_gcmdecryptdone@Base 2.5.0
+       skipjack_gcm@Base 2.5.0
+       skipjack_ocb1init@Base 2.5.0
+       skipjack_ocb1reinit@Base 2.5.0
+       skipjack_ocb1setkey@Base 2.5.0
+       skipjack_ocb1policy@Base 2.5.0
+       skipjack_ocb1noncesz@Base 2.5.0
+       skipjack_ocb1tagsz@Base 2.5.0
+       skipjack_ocb1aadinit@Base 2.5.0
+       skipjack_ocb1aadhash@Base 2.5.0
+       skipjack_ocb1aadtag@Base 2.5.0
+       skipjack_ocb1encrypt@Base 2.5.0
+       skipjack_ocb1decrypt@Base 2.5.0
+       skipjack_ocb1encryptdone@Base 2.5.0
+       skipjack_ocb1decryptdone@Base 2.5.0
+       skipjack_ocb1@Base 2.5.0
+       skipjack_ocb3init@Base 2.5.0
+       skipjack_ocb3step@Base 2.5.0
+       skipjack_ocb3reinit@Base 2.5.0
+       skipjack_ocb3setkey@Base 2.5.0
+       skipjack_ocb3noncesz@Base 2.5.0
+       skipjack_ocb3aadinit@Base 2.5.0
+       skipjack_ocb3aadhash@Base 2.5.0
+       skipjack_ocb3encrypt@Base 2.5.0
+       skipjack_ocb3decrypt@Base 2.5.0
+       skipjack_ocb3encryptdone@Base 2.5.0
+       skipjack_ocb3decryptdone@Base 2.5.0
+       skipjack_ocb3tagsz@Base 2.5.0
+       skipjack_ocb3@Base 2.5.0
+       skipjack_omacmasks@Base 2.5.0
+       skipjack_omacpolicy@Base 2.5.0
+       skipjack_omacdone@Base 2.5.0
+       skipjack_cmacinit@Base 2.5.0
+       skipjack_cmacsetkey@Base 2.5.0
+       skipjack_cmachash@Base 2.5.0
+       skipjack_cmacdone@Base 2.5.0
+       skipjack_cmac@Base 2.5.0
+       skipjack_pmac1init@Base 2.5.0
+       skipjack_pmac1setkey@Base 2.5.0
+       skipjack_pmac1hash@Base 2.5.0
+       skipjack_pmac1done@Base 2.5.0
+       skipjack_pmac1@Base 2.5.0
 
 ## square
        square_init@Base 2.0.0
@@ -1640,6 +3097,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        square_counterbdry@Base 2.0.0
        square_counter@Base 2.0.0
        square_counterrand@Base 2.0.0
+       square_ccminit@Base 2.5.0
+       square_ccmreinit@Base 2.5.0
+       square_ccmnoncesz@Base 2.5.0
+       square_ccmtagsz@Base 2.5.0
+       square_ccmaadhash@Base 2.5.0
+       square_ccmencrypt@Base 2.5.0
+       square_ccmdecrypt@Base 2.5.0
+       square_ccmencryptdone@Base 2.5.0
+       square_ccmdecryptdone@Base 2.5.0
+       square_ccm@Base 2.5.0
+       square_eaxinit@Base 2.5.0
+       square_eaxreinit@Base 2.5.0
+       square_eaxsetkey@Base 2.5.0
+       square_eaxnoncesz@Base 2.5.0
+       square_eaxtagsz@Base 2.5.0
+       square_eaxaadinit@Base 2.5.0
+       square_eaxaadhash@Base 2.5.0
+       square_eaxencrypt@Base 2.5.0
+       square_eaxdecrypt@Base 2.5.0
+       square_eaxencryptdone@Base 2.5.0
+       square_eaxdecryptdone@Base 2.5.0
+       square_eax@Base 2.5.0
+       square_gcminit@Base 2.5.0
+       square_gcmreinit@Base 2.5.0
+       square_gcmsetkey@Base 2.5.0
+       square_gcmnoncesz@Base 2.5.0
+       square_gcmtagsz@Base 2.5.0
+       square_gcmaadinit@Base 2.5.0
+       square_gcmaadhash@Base 2.5.0
+       square_gcmencrypt@Base 2.5.0
+       square_gcmdecrypt@Base 2.5.0
+       square_gcmencryptdone@Base 2.5.0
+       square_gcmdecryptdone@Base 2.5.0
+       square_gcm@Base 2.5.0
+       square_ocb1init@Base 2.5.0
+       square_ocb1reinit@Base 2.5.0
+       square_ocb1setkey@Base 2.5.0
+       square_ocb1policy@Base 2.5.0
+       square_ocb1noncesz@Base 2.5.0
+       square_ocb1tagsz@Base 2.5.0
+       square_ocb1aadinit@Base 2.5.0
+       square_ocb1aadhash@Base 2.5.0
+       square_ocb1aadtag@Base 2.5.0
+       square_ocb1encrypt@Base 2.5.0
+       square_ocb1decrypt@Base 2.5.0
+       square_ocb1encryptdone@Base 2.5.0
+       square_ocb1decryptdone@Base 2.5.0
+       square_ocb1@Base 2.5.0
+       square_ocb3init@Base 2.5.0
+       square_ocb3step@Base 2.5.0
+       square_ocb3reinit@Base 2.5.0
+       square_ocb3setkey@Base 2.5.0
+       square_ocb3noncesz@Base 2.5.0
+       square_ocb3aadinit@Base 2.5.0
+       square_ocb3aadhash@Base 2.5.0
+       square_ocb3encrypt@Base 2.5.0
+       square_ocb3decrypt@Base 2.5.0
+       square_ocb3encryptdone@Base 2.5.0
+       square_ocb3decryptdone@Base 2.5.0
+       square_ocb3tagsz@Base 2.5.0
+       square_ocb3@Base 2.5.0
+       square_omacmasks@Base 2.5.0
+       square_omacpolicy@Base 2.5.0
+       square_omacdone@Base 2.5.0
+       square_cmacinit@Base 2.5.0
+       square_cmacsetkey@Base 2.5.0
+       square_cmachash@Base 2.5.0
+       square_cmacdone@Base 2.5.0
+       square_cmac@Base 2.5.0
+       square_pmac1init@Base 2.5.0
+       square_pmac1setkey@Base 2.5.0
+       square_pmac1hash@Base 2.5.0
+       square_pmac1done@Base 2.5.0
+       square_pmac1@Base 2.5.0
 
 ## tea
        tea_init@Base 2.0.0
@@ -1682,6 +3213,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        tea_counterbdry@Base 2.0.0
        tea_counter@Base 2.0.0
        tea_counterrand@Base 2.0.0
+       tea_ccminit@Base 2.5.0
+       tea_ccmreinit@Base 2.5.0
+       tea_ccmnoncesz@Base 2.5.0
+       tea_ccmtagsz@Base 2.5.0
+       tea_ccmaadhash@Base 2.5.0
+       tea_ccmencrypt@Base 2.5.0
+       tea_ccmdecrypt@Base 2.5.0
+       tea_ccmencryptdone@Base 2.5.0
+       tea_ccmdecryptdone@Base 2.5.0
+       tea_ccm@Base 2.5.0
+       tea_eaxinit@Base 2.5.0
+       tea_eaxreinit@Base 2.5.0
+       tea_eaxsetkey@Base 2.5.0
+       tea_eaxnoncesz@Base 2.5.0
+       tea_eaxtagsz@Base 2.5.0
+       tea_eaxaadinit@Base 2.5.0
+       tea_eaxaadhash@Base 2.5.0
+       tea_eaxencrypt@Base 2.5.0
+       tea_eaxdecrypt@Base 2.5.0
+       tea_eaxencryptdone@Base 2.5.0
+       tea_eaxdecryptdone@Base 2.5.0
+       tea_eax@Base 2.5.0
+       tea_gcminit@Base 2.5.0
+       tea_gcmreinit@Base 2.5.0
+       tea_gcmsetkey@Base 2.5.0
+       tea_gcmnoncesz@Base 2.5.0
+       tea_gcmtagsz@Base 2.5.0
+       tea_gcmaadinit@Base 2.5.0
+       tea_gcmaadhash@Base 2.5.0
+       tea_gcmencrypt@Base 2.5.0
+       tea_gcmdecrypt@Base 2.5.0
+       tea_gcmencryptdone@Base 2.5.0
+       tea_gcmdecryptdone@Base 2.5.0
+       tea_gcm@Base 2.5.0
+       tea_ocb1init@Base 2.5.0
+       tea_ocb1reinit@Base 2.5.0
+       tea_ocb1setkey@Base 2.5.0
+       tea_ocb1policy@Base 2.5.0
+       tea_ocb1noncesz@Base 2.5.0
+       tea_ocb1tagsz@Base 2.5.0
+       tea_ocb1aadinit@Base 2.5.0
+       tea_ocb1aadhash@Base 2.5.0
+       tea_ocb1aadtag@Base 2.5.0
+       tea_ocb1encrypt@Base 2.5.0
+       tea_ocb1decrypt@Base 2.5.0
+       tea_ocb1encryptdone@Base 2.5.0
+       tea_ocb1decryptdone@Base 2.5.0
+       tea_ocb1@Base 2.5.0
+       tea_ocb3init@Base 2.5.0
+       tea_ocb3step@Base 2.5.0
+       tea_ocb3reinit@Base 2.5.0
+       tea_ocb3setkey@Base 2.5.0
+       tea_ocb3noncesz@Base 2.5.0
+       tea_ocb3aadinit@Base 2.5.0
+       tea_ocb3aadhash@Base 2.5.0
+       tea_ocb3encrypt@Base 2.5.0
+       tea_ocb3decrypt@Base 2.5.0
+       tea_ocb3encryptdone@Base 2.5.0
+       tea_ocb3decryptdone@Base 2.5.0
+       tea_ocb3tagsz@Base 2.5.0
+       tea_ocb3@Base 2.5.0
+       tea_omacmasks@Base 2.5.0
+       tea_omacpolicy@Base 2.5.0
+       tea_omacdone@Base 2.5.0
+       tea_cmacinit@Base 2.5.0
+       tea_cmacsetkey@Base 2.5.0
+       tea_cmachash@Base 2.5.0
+       tea_cmacdone@Base 2.5.0
+       tea_cmac@Base 2.5.0
+       tea_pmac1init@Base 2.5.0
+       tea_pmac1setkey@Base 2.5.0
+       tea_pmac1hash@Base 2.5.0
+       tea_pmac1done@Base 2.5.0
+       tea_pmac1@Base 2.5.0
 
 ## twofish
        twofish_fkinit@Base 2.0.0
@@ -1732,6 +3337,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        twofish_counterbdry@Base 2.0.0
        twofish_counter@Base 2.0.0
        twofish_counterrand@Base 2.0.0
+       twofish_ccminit@Base 2.5.0
+       twofish_ccmreinit@Base 2.5.0
+       twofish_ccmnoncesz@Base 2.5.0
+       twofish_ccmtagsz@Base 2.5.0
+       twofish_ccmaadhash@Base 2.5.0
+       twofish_ccmencrypt@Base 2.5.0
+       twofish_ccmdecrypt@Base 2.5.0
+       twofish_ccmencryptdone@Base 2.5.0
+       twofish_ccmdecryptdone@Base 2.5.0
+       twofish_ccm@Base 2.5.0
+       twofish_eaxinit@Base 2.5.0
+       twofish_eaxreinit@Base 2.5.0
+       twofish_eaxsetkey@Base 2.5.0
+       twofish_eaxnoncesz@Base 2.5.0
+       twofish_eaxtagsz@Base 2.5.0
+       twofish_eaxaadinit@Base 2.5.0
+       twofish_eaxaadhash@Base 2.5.0
+       twofish_eaxencrypt@Base 2.5.0
+       twofish_eaxdecrypt@Base 2.5.0
+       twofish_eaxencryptdone@Base 2.5.0
+       twofish_eaxdecryptdone@Base 2.5.0
+       twofish_eax@Base 2.5.0
+       twofish_gcminit@Base 2.5.0
+       twofish_gcmreinit@Base 2.5.0
+       twofish_gcmsetkey@Base 2.5.0
+       twofish_gcmnoncesz@Base 2.5.0
+       twofish_gcmtagsz@Base 2.5.0
+       twofish_gcmaadinit@Base 2.5.0
+       twofish_gcmaadhash@Base 2.5.0
+       twofish_gcmencrypt@Base 2.5.0
+       twofish_gcmdecrypt@Base 2.5.0
+       twofish_gcmencryptdone@Base 2.5.0
+       twofish_gcmdecryptdone@Base 2.5.0
+       twofish_gcm@Base 2.5.0
+       twofish_ocb1init@Base 2.5.0
+       twofish_ocb1reinit@Base 2.5.0
+       twofish_ocb1setkey@Base 2.5.0
+       twofish_ocb1policy@Base 2.5.0
+       twofish_ocb1noncesz@Base 2.5.0
+       twofish_ocb1tagsz@Base 2.5.0
+       twofish_ocb1aadinit@Base 2.5.0
+       twofish_ocb1aadhash@Base 2.5.0
+       twofish_ocb1aadtag@Base 2.5.0
+       twofish_ocb1encrypt@Base 2.5.0
+       twofish_ocb1decrypt@Base 2.5.0
+       twofish_ocb1encryptdone@Base 2.5.0
+       twofish_ocb1decryptdone@Base 2.5.0
+       twofish_ocb1@Base 2.5.0
+       twofish_ocb3init@Base 2.5.0
+       twofish_ocb3step@Base 2.5.0
+       twofish_ocb3reinit@Base 2.5.0
+       twofish_ocb3setkey@Base 2.5.0
+       twofish_ocb3noncesz@Base 2.5.0
+       twofish_ocb3aadinit@Base 2.5.0
+       twofish_ocb3aadhash@Base 2.5.0
+       twofish_ocb3encrypt@Base 2.5.0
+       twofish_ocb3decrypt@Base 2.5.0
+       twofish_ocb3encryptdone@Base 2.5.0
+       twofish_ocb3decryptdone@Base 2.5.0
+       twofish_ocb3tagsz@Base 2.5.0
+       twofish_ocb3@Base 2.5.0
+       twofish_omacmasks@Base 2.5.0
+       twofish_omacpolicy@Base 2.5.0
+       twofish_omacdone@Base 2.5.0
+       twofish_cmacinit@Base 2.5.0
+       twofish_cmacsetkey@Base 2.5.0
+       twofish_cmachash@Base 2.5.0
+       twofish_cmacdone@Base 2.5.0
+       twofish_cmac@Base 2.5.0
+       twofish_pmac1init@Base 2.5.0
+       twofish_pmac1setkey@Base 2.5.0
+       twofish_pmac1hash@Base 2.5.0
+       twofish_pmac1done@Base 2.5.0
+       twofish_pmac1@Base 2.5.0
 
 ## xtea
        xtea_init@Base 2.0.0
@@ -1774,6 +3453,80 @@ libcatacomb.so.2 catacomb2 #MINVER#
        xtea_counterbdry@Base 2.0.0
        xtea_counter@Base 2.0.0
        xtea_counterrand@Base 2.0.0
+       xtea_ccminit@Base 2.5.0
+       xtea_ccmreinit@Base 2.5.0
+       xtea_ccmnoncesz@Base 2.5.0
+       xtea_ccmtagsz@Base 2.5.0
+       xtea_ccmaadhash@Base 2.5.0
+       xtea_ccmencrypt@Base 2.5.0
+       xtea_ccmdecrypt@Base 2.5.0
+       xtea_ccmencryptdone@Base 2.5.0
+       xtea_ccmdecryptdone@Base 2.5.0
+       xtea_ccm@Base 2.5.0
+       xtea_eaxinit@Base 2.5.0
+       xtea_eaxreinit@Base 2.5.0
+       xtea_eaxsetkey@Base 2.5.0
+       xtea_eaxnoncesz@Base 2.5.0
+       xtea_eaxtagsz@Base 2.5.0
+       xtea_eaxaadinit@Base 2.5.0
+       xtea_eaxaadhash@Base 2.5.0
+       xtea_eaxencrypt@Base 2.5.0
+       xtea_eaxdecrypt@Base 2.5.0
+       xtea_eaxencryptdone@Base 2.5.0
+       xtea_eaxdecryptdone@Base 2.5.0
+       xtea_eax@Base 2.5.0
+       xtea_gcminit@Base 2.5.0
+       xtea_gcmreinit@Base 2.5.0
+       xtea_gcmsetkey@Base 2.5.0
+       xtea_gcmnoncesz@Base 2.5.0
+       xtea_gcmtagsz@Base 2.5.0
+       xtea_gcmaadinit@Base 2.5.0
+       xtea_gcmaadhash@Base 2.5.0
+       xtea_gcmencrypt@Base 2.5.0
+       xtea_gcmdecrypt@Base 2.5.0
+       xtea_gcmencryptdone@Base 2.5.0
+       xtea_gcmdecryptdone@Base 2.5.0
+       xtea_gcm@Base 2.5.0
+       xtea_ocb1init@Base 2.5.0
+       xtea_ocb1reinit@Base 2.5.0
+       xtea_ocb1setkey@Base 2.5.0
+       xtea_ocb1policy@Base 2.5.0
+       xtea_ocb1noncesz@Base 2.5.0
+       xtea_ocb1tagsz@Base 2.5.0
+       xtea_ocb1aadinit@Base 2.5.0
+       xtea_ocb1aadhash@Base 2.5.0
+       xtea_ocb1aadtag@Base 2.5.0
+       xtea_ocb1encrypt@Base 2.5.0
+       xtea_ocb1decrypt@Base 2.5.0
+       xtea_ocb1encryptdone@Base 2.5.0
+       xtea_ocb1decryptdone@Base 2.5.0
+       xtea_ocb1@Base 2.5.0
+       xtea_ocb3init@Base 2.5.0
+       xtea_ocb3step@Base 2.5.0
+       xtea_ocb3reinit@Base 2.5.0
+       xtea_ocb3setkey@Base 2.5.0
+       xtea_ocb3noncesz@Base 2.5.0
+       xtea_ocb3aadinit@Base 2.5.0
+       xtea_ocb3aadhash@Base 2.5.0
+       xtea_ocb3encrypt@Base 2.5.0
+       xtea_ocb3decrypt@Base 2.5.0
+       xtea_ocb3encryptdone@Base 2.5.0
+       xtea_ocb3decryptdone@Base 2.5.0
+       xtea_ocb3tagsz@Base 2.5.0
+       xtea_ocb3@Base 2.5.0
+       xtea_omacmasks@Base 2.5.0
+       xtea_omacpolicy@Base 2.5.0
+       xtea_omacdone@Base 2.5.0
+       xtea_cmacinit@Base 2.5.0
+       xtea_cmacsetkey@Base 2.5.0
+       xtea_cmachash@Base 2.5.0
+       xtea_cmacdone@Base 2.5.0
+       xtea_cmac@Base 2.5.0
+       xtea_pmac1init@Base 2.5.0
+       xtea_pmac1setkey@Base 2.5.0
+       xtea_pmac1hash@Base 2.5.0
+       xtea_pmac1done@Base 2.5.0
+       xtea_pmac1@Base 2.5.0
 
 ## gcrc32
        gcrc32@Base 2.1.0
@@ -2468,8 +4221,8 @@ libcatacomb.so.2 catacomb2 #MINVER#
 
 ## dh
        dh_gen@Base 2.1.1
-       dh_kcdsagen@Base 2.1.1
-       dh_limlee@Base 2.2.4
+       dh_kcdsagen@Base 2.5.1+
+       dh_limlee@Base 2.5.1+
        dh_checkparam@Base 2.1.1
        dh_parse@Base 2.1.1
        dhbin_parse@Base 2.1.1
@@ -2600,9 +4353,9 @@ libcatacomb.so.2 catacomb2 #MINVER#
        key_structsteal@Base 2.1.1
        key_mksubkeyiter@Base 2.1.1
        key_nextsubkey@Base 2.1.1
-       key_copydata@Base 2.1.2
+       key_copydata@Base 2.5.1+
        key_incref@Base 2.1.1
-       key_split@Base 2.1.1
+       key_split@Base 2.5.1+
        key_drop@Base 2.1.1
        key_destroy@Base 2.1.1
        key_do@Base 2.1.1
@@ -2660,7 +4413,7 @@ libcatacomb.so.2 catacomb2 #MINVER#
 
 ## key-misc
        key_byid@Base 2.1.1
-       key_bytag@Base 2.1.1
+       key_bytag@Base 2.5.1+
        key_bytype@Base 2.1.1
        key_qtag@Base 2.1.1
        key_expired@Base 2.1.1
index 6079fd7..bc7bcb7 100644 (file)
@@ -1,3 +1,28 @@
+catacomb (2.5.1) experimental; urgency=medium
+
+  * Merge changes from 2.4.4.
+
+ -- Mark Wooding <mdw@distorted.org.uk>  Sun, 29 Sep 2019 17:50:59 +0100
+
+catacomb (2.5.0) experimental; urgency=medium
+
+  * catacomb: MACs based on blockciphers: PMAC1 and CMAC (also known as
+    OMAC).
+  * catacomb: Authenticated Encryption with Additional Data (AEAD)
+    schemes.  Some based on blockciphers: CCM, EAX, GCM (with CPU-specific
+    acceleration), OCB1 and OCB3 (OCB2 is broken).  Also Salsa20 and
+    ChaCha20 with Poly1305: the RFC7539 scheme, and the NaCl `secret_box'
+    transform.
+  * catacomb: Implement Grantham's Frobenius test.  Combine it with
+    Rabin--Miller, as Baillie--PSW, for testing given primes.
+  * catacomb-bin (catcrypt): Support AEAD schemes for bulk crypto.
+  * catacomb-bin (perftest): Options for batching; report cycle counts
+    where available.
+  * Many internal improvements: better documentation, debugging, testing,
+    etc.
+
+ -- Mark Wooding <mdw@distorted.org.uk>  Sat, 21 Sep 2019 21:26:44 +0100
+
 catacomb (2.4.5) experimental; urgency=medium
 
   * catacomb: Fix memory leak in key-file error handling.
index be186cf..c22c255 100644 (file)
@@ -2,7 +2,7 @@ Source: catacomb
 Section: libs
 Priority: extra
 Build-Depends: debhelper (>= 10), python, valgrind [!armel], pkg-config,
- mlib-dev (>= 2.2.2.1)
+ mlib-dev (>= 2.3.0)
 Maintainer: Mark Wooding <mdw@distorted.org.uk>
 Standards-Version: 3.1.1
 
index 21ff172..7c4ffed 100644 (file)
@@ -246,9 +246,10 @@ libmath_la_SOURCES += pfilt.c
 pkginclude_HEADERS     += pgen.h
 libmath_la_SOURCES     += pgen.c
 libmath_la_SOURCES     += pgen-gcd.c
+libmath_la_SOURCES     += pgen-granfrob.c
 libmath_la_SOURCES     += pgen-simul.c
 libmath_la_SOURCES     += pgen-stdev.c
-TESTS                  += pgen.t$(EXEEXT)
+TESTS                  += pgen.t$(EXEEXT) pgen-granfrob.t$(EXEEXT)
 EXTRA_DIST             += t/pgen
 
 ## Finding primitive elements in finite fields.
index 78844be..a886465 100644 (file)
@@ -50,7 +50,6 @@ typedef uint32 upiece;  typedef uint64 udblpiece;
 
 #define M26 0x03ffffffu
 #define M25 0x01ffffffu
-#define B26 0x04000000u
 #define B25 0x02000000u
 #define B24 0x01000000u
 
@@ -83,11 +82,10 @@ typedef uint16 upiece;  typedef uint32 udblpiece;
     ((i) == 5 || (i) == 10 || (i) == 15 || (i) == 20 || (i) == 25 ? 9 : 10)
 #define NPIECE 26
 
-#define B10 0x0400
-#define B9 0x200
-#define B8 0x100
 #define M10 0x3ff
 #define M9 0x1ff
+#define B9 0x200
+#define B8 0x100
 
 #endif
 
index 9061a74..1b09b58 100644 (file)
@@ -51,10 +51,8 @@ typedef uint32 upiece; typedef uint64 udblpiece;
 #define NPIECE 16
 #define P p28
 
-#define B28 0x10000000u
 #define B27 0x08000000u
 #define M28 0x0fffffffu
-#define M27 0x07ffffffu
 #define M32 0xffffffffu
 
 #elif FGOLDI_IMPL == 12
@@ -70,12 +68,10 @@ typedef uint16 upiece; typedef uint32 udblpiece;
 #define NPIECE 40
 #define P p12
 
-#define B12 0x1000u
 #define B11 0x0800u
 #define B10 0x0400u
 #define M12 0xfffu
 #define M11 0x7ffu
-#define M10 0x3ffu
 #define M8 0xffu
 
 #endif
index 2dbe418..bf19fe8 100644 (file)
@@ -71,12 +71,32 @@ mp *mp_sqrt(mp *d, mp *a)
 
   /* --- Main approximation --- *
    *
-   * We use the Newton-Raphson recurrence relation
+   * The Newton--Raphson method finds approximate zeroes of a function by
+   * starting with a guess and repeatedly refining the guess by approximating
+   * the function near the guess by its tangent at the guess
+   * %$x$%-coordinate, using where the tangent cuts the %$x$%-axis as the new
+   * guess.
    *
-   *   %$x_{i+1} = x_i - \frac{x_i^2 - a}{2 x_i}$%
+   * Given a function %$f(x)$% and a guess %$x_i$%, the tangent has the
+   * equation %$y = f(x_i) + f'(x_i) (x - x_i)$%, which is zero when
    *
-   * We inspect the term %$q = x^2 - a$% to see when to stop.  Increasing
-   * %$x$% is pointless when %$-q < 2 x + 1$%.
+   *   %$\displaystyle x = x_i - \frac{f(x_i)}{f'(x_i)}
+   *
+   * We set %$f(x) = x^2 - a$%, so our recurrence will be
+   *
+   *   %$\displaystyle x_{i+1} = x_i - \frac{x_i^2 - a}{2 x_i}$%
+   *
+   * It's possible to simplify this, but it's useful to see %$q = x_i^2 - a$%
+   * so that we know when to stop.  We want the largest integer not larger
+   * than the true square root.  If %$q > 0$% then %$x_i$% is definitely too
+   * large, and we should decrease it by at least one even if the adjustment
+   * term %$(x_i^2 - a)/2 x$% is less than one.
+   *
+   * Suppose, then, that %$q \le 0$%.  Then %$(x_i + 1)^2 - a = {}$%
+   * $%x_i^2 + 2 x_i + 1 - a = q + 2 x_i + 1$%.  Hence, if %$q \ge -2 x_i$%
+   * then %$x_i + 1$% is an overestimate and we should settle where we are.
+   * Otherwise, %$x_i + 1$% is an underestimate -- but, in this case the
+   * adjustment will always be at least one.
    */
 
   for (;;) {
index f8a2611..094ac40 100644 (file)
@@ -90,19 +90,25 @@ static void simple_redccore(mpw *dv, mpw *dvl, const mpw *mv,
 
 #if CPUFAM_X86
   MAYBE_REDC4(x86_sse2)
+  MAYBE_REDC4(x86_avx)
 #endif
 
 #if CPUFAM_AMD64
   MAYBE_REDC4(amd64_sse2)
+  MAYBE_REDC4(amd64_avx)
 #endif
 
 static redccore__functype *pick_redccore(void)
 {
 #if CPUFAM_X86
+  DISPATCH_PICK_COND(mpmont_reduce, maybe_redc4_x86_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(mpmont_reduce, maybe_redc4_x86_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
 #if CPUFAM_AMD64
+  DISPATCH_PICK_COND(mpmont_reduce, maybe_redc4_amd64_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(mpmont_reduce, maybe_redc4_amd64_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
@@ -190,19 +196,25 @@ static void simple_mulcore(mpw *dv, mpw *dvl,
 
 #if CPUFAM_X86
   MAYBE_MUL4(x86_sse2)
+  MAYBE_MUL4(x86_avx)
 #endif
 
 #if CPUFAM_AMD64
   MAYBE_MUL4(amd64_sse2)
+  MAYBE_MUL4(amd64_avx)
 #endif
 
 static mulcore__functype *pick_mulcore(void)
 {
 #if CPUFAM_X86
+  DISPATCH_PICK_COND(mpmont_mul, maybe_mul4_x86_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(mpmont_mul, maybe_mul4_x86_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
 #if CPUFAM_AMD64
+  DISPATCH_PICK_COND(mpmont_mul, maybe_mul4_amd64_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(mpmont_mul, maybe_mul4_amd64_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
index 94befa4..d313765 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
-///--------------------------------------------------------------------------
-/// Prologue.
-
        .arch   pentium4
+
        .text
 
 ///--------------------------------------------------------------------------
 .macro mulcore r, i, slo, shi, d0, d1=nil, d2=nil, d3=nil
        // Multiply R_I by the expanded operand SLO/SHI, and leave the pieces
        // of the product in registers D0, D1, D2, D3.
-       pshufd  \d0, \r, SHUF(3, \i, 3, \i) // (r_i, ?, r_i, ?)
+       pshufd  \d0, \r, SHUF(\i, 3, \i, 3) // (r_i, ?; r_i, ?)
   .ifnes "\d1", "nil"
-       movdqa  \d1, \slo               // (s'_0, s'_1, s''_0, s''_1)
+       movdqa  \d1, \slo               // (s'_0, s'_1; s''_0, s''_1)
   .endif
   .ifnes "\d3", "nil"
-       movdqa  \d3, \shi               // (s'_2, s'_3, s''_2, s''_3)
+       movdqa  \d3, \shi               // (s'_2, s'_3; s''_2, s''_3)
   .endif
   .ifnes "\d1", "nil"
-       psrldq  \d1, 4                  // (s'_1, s''_0, s''_1, 0)
+       psrldq  \d1, 4                  // (s'_1, s''_0; s''_1, 0)
   .endif
   .ifnes "\d2", "nil"
-       movdqa  \d2, \d0                // another copy of (r_i, ?, r_i, ?)
+       movdqa  \d2, \d0                // another copy of (r_i, ?; r_i, ?)
   .endif
   .ifnes "\d3", "nil"
-       psrldq  \d3, 4                  // (s'_3, s''_2, s''_3, 0)
+       psrldq  \d3, 4                  // (s'_3, s''_2; s''_3, 0)
   .endif
   .ifnes "\d1", "nil"
-       pmuludq \d1, \d0                // (r_i s'_1, r_i s''_1)
+       pmuludq \d1, \d0                // (r_i s'_1; r_i s''_1)
   .endif
   .ifnes "\d3", "nil"
-       pmuludq \d3, \d0                // (r_i s'_3, r_i s''_3)
+       pmuludq \d3, \d0                // (r_i s'_3; r_i s''_3)
   .endif
   .ifnes "\d2", "nil"
-       pmuludq \d2, \shi               // (r_i s'_2, r_i s''_2)
+       pmuludq \d2, \shi               // (r_i s'_2; r_i s''_2)
   .endif
-       pmuludq \d0, \slo               // (r_i s'_0, r_i s''_0)
+       pmuludq \d0, \slo               // (r_i s'_0; r_i s''_0)
 .endm
 
 .macro accum   c0, c1=nil, c2=nil, c3=nil
        // lane 0 or 1 of D; the high two lanes of D are clobbered.  On
        // completion, XMM3 is clobbered.  If CC is `nil', then the
        // contribution which would have been added to it is left in C.
-       pshufd  xmm3, \c, SHUF(2, 3, 3, 3) // (?, ?, ?, t = c'' mod B)
-       psrldq  xmm3, 12                // (t, 0, 0, 0) = (t, 0)
-       pslldq  xmm3, 2                 // (t b, 0)
-       paddq   \c, xmm3                // (c' + t b, c'')
+       pshufd  xmm3, \c, SHUF(3, 3, 3, 2) // (?, ?; ?, t = c'' mod B)
+       psrldq  xmm3, 12                // (t, 0; 0, 0) = (t; 0)
+       pslldq  xmm3, 2                 // (t b; 0)
+       paddq   \c, xmm3                // (c' + t b; c'')
   .ifeqs "\pos", "lo"
        movdqa  \d, \c
   .else
        // of the value represented in C are written at POS in D, and the
        // remaining bits are left at the bottom of T.
        movdqa  \t, \c
-       psllq   \t, 16                  // (?, c'' b)
-       pslldq  \c, 8                   // (0, c')
-       paddq   \t, \c                  // (?, c' + c'' b)
-       psrldq  \t, 8                   // c' + c'' b
+       psllq   \t, 16                  // (?; c'' b)
+       pslldq  \c, 8                   // (0; c')
+       paddq   \t, \c                  // (?; c' + c'' b)
+       psrldq  \t, 8                   // (c' + c'' b; 0) = (c; 0)
   .ifeqs "\pos", "lo"
        movdqa  \d, \t
   .else
        punpckldq \d, \t
   .endif
-       psrldq  \t, 4                   // floor((c' + c'' b)/B)
+       psrldq  \t, 4                   // (floor(c/B); 0)
 .endm
 
 .macro expand  z, a, b, c=nil, d=nil
        // On entry, A and C hold packed 128-bit values, and Z is zero.  On
        // exit, A:B and C:D together hold the same values in expanded
        // form.  If C is `nil', then only expand A to A:B.
-       movdqa  \b, \a                  // (a_0, a_1, a_2, a_3)
+       movdqa  \b, \a                  // (a_0, a_1; a_2, a_3)
   .ifnes "\c", "nil"
-       movdqa  \d, \c                  // (c_0, c_1, c_2, c_3)
+       movdqa  \d, \c                  // (c_0, c_1; c_2, c_3)
   .endif
-       punpcklwd \a, \z                // (a'_0, a''_0, a'_1, a''_1)
-       punpckhwd \b, \z                // (a'_2, a''_2, a'_3, a''_3)
+       punpcklwd \a, \z                // (a'_0, a''_0; a'_1, a''_1)
+       punpckhwd \b, \z                // (a'_2, a''_2; a'_3, a''_3)
   .ifnes "\c", "nil"
-       punpcklwd \c, \z                // (c'_0, c''_0, c'_1, c''_1)
-       punpckhwd \d, \z                // (c'_2, c''_2, c'_3, c''_3)
+       punpcklwd \c, \z                // (c'_0, c''_0; c'_1, c''_1)
+       punpckhwd \d, \z                // (c'_2, c''_2; c'_3, c''_3)
   .endif
-       pshufd  \a, \a, SHUF(3, 1, 2, 0) // (a'_0, a'_1, a''_0, a''_1)
-       pshufd  \b, \b, SHUF(3, 1, 2, 0) // (a'_2, a'_3, a''_2, a''_3)
+       pshufd  \a, \a, SHUF(0, 2, 1, 3) // (a'_0, a'_1; a''_0, a''_1)
+       pshufd  \b, \b, SHUF(0, 2, 1, 3) // (a'_2, a'_3; a''_2, a''_3)
   .ifnes "\c", "nil"
-       pshufd  \c, \c, SHUF(3, 1, 2, 0) // (c'_0, c'_1, c''_0, c''_1)
-       pshufd  \d, \d, SHUF(3, 1, 2, 0) // (c'_2, c'_3, c''_2, c''_3)
+       pshufd  \c, \c, SHUF(0, 2, 1, 3) // (c'_0, c'_1; c''_0, c''_1)
+       pshufd  \d, \d, SHUF(0, 2, 1, 3) // (c'_2, c'_3; c''_2, c''_3)
   .endif
 .endm
 
        // we can do that, we must gather them together.
        movdqa  \t, \c0
        movdqa  \u, \c1
-       punpcklqdq \t, \c2              // (y'_0, y'_2)
-       punpckhqdq \c0, \c2             // (y''_0, y''_2)
-       punpcklqdq \u, \c3              // (y'_1, y'_3)
-       punpckhqdq \c1, \c3             // (y''_1, y''_3)
+       punpcklqdq \t, \c2              // (y'_0; y'_2)
+       punpckhqdq \c0, \c2             // (y''_0; y''_2)
+       punpcklqdq \u, \c3              // (y'_1; y'_3)
+       punpckhqdq \c1, \c3             // (y''_1; y''_3)
 
        // Now split the double-prime pieces.  The high (up to) 48 bits will
        // go up; the low 16 bits go down.
        movdqa  \c3, \c1
        psllq   \c2, 48
        psllq   \c3, 48
-       psrlq   \c0, 16                 // high parts of (y''_0, y''_2)
-       psrlq   \c1, 16                 // high parts of (y''_1, y''_3)
-       psrlq   \c2, 32                 // low parts of (y''_0, y''_2)
-       psrlq   \c3, 32                 // low parts of (y''_1, y''_3)
+       psrlq   \c0, 16                 // high parts of (y''_0; y''_2)
+       psrlq   \c1, 16                 // high parts of (y''_1; y''_3)
+       psrlq   \c2, 32                 // low parts of (y''_0; y''_2)
+       psrlq   \c3, 32                 // low parts of (y''_1; y''_3)
   .ifnes "\hi", "nil"
        movdqa  \hi, \c1
   .endif
-       pslldq  \c1, 8                  // high part of (0, y''_1)
+       pslldq  \c1, 8                  // high part of (0; y''_1)
 
        paddq   \t, \c2                 // propagate down
        paddq   \u, \c3
-       paddq   \t, \c1                 // and up: (y_0, y_2)
-       paddq   \u, \c0                 // (y_1, y_3)
+       paddq   \t, \c1                 // and up: (y_0; y_2)
+       paddq   \u, \c0                 // (y_1; y_3)
   .ifnes "\hi", "nil"
-       psrldq  \hi, 8                  // high part of (y''_3, 0)
+       psrldq  \hi, 8                  // high part of (y''_3; 0)
   .endif
 
        // Finally extract the answer.  This complicated dance is better than
        // storing to memory and loading, because the piecemeal stores
        // inhibit store forwarding.
-       movdqa  \c3, \t                 // (y_0, y_1)
-       movdqa  \lo, \t                 // (y^*_0, ?, ?, ?)
-       psrldq  \t, 8                   // (y_2, 0)
-       psrlq   \c3, 32                 // (floor(y_0/B), ?)
-       paddq   \c3, \u                 // (y_1 + floor(y_0/B), ?)
-       movdqa  \c1, \c3                // (y^*_1, ?, ?, ?)
-       psrldq  \u, 8                   // (y_3, 0)
-       psrlq   \c3, 32                 // (floor((y_1 B + y_0)/B^2, ?)
-       paddq   \c3, \t                 // (y_2 + floor((y_1 B + y_0)/B^2, ?)
-       punpckldq \lo, \c3              // (y^*_0, y^*_2, ?, ?)
-       psrlq   \c3, 32             // (floor((y_2 B^2 + y_1 B + y_0)/B^3, ?)
-       paddq   \c3, \u       // (y_3 + floor((y_2 B^2 + y_1 B + y_0)/B^3, ?)
+       movdqa  \c3, \t                 // (y_0; ?)
+       movdqa  \lo, \t                 // (y^*_0, ?; ?, ?)
+       psrldq  \t, 8                   // (y_2; 0)
+       psrlq   \c3, 32                 // (floor(y_0/B); ?)
+       paddq   \c3, \u                 // (y_1 + floor(y_0/B); ?)
+       movdqa  \c1, \c3                // (y^*_1, ?; ?, ?)
+       psrldq  \u, 8                   // (y_3; 0)
+       psrlq   \c3, 32                 // (floor((y_1 B + y_0)/B^2; ?)
+       paddq   \c3, \t                 // (y_2 + floor((y_1 B + y_0)/B^2; ?)
+       punpckldq \lo, \c3              // (y^*_0, y^*_2; ?, ?)
+       psrlq   \c3, 32             // (floor((y_2 B^2 + y_1 B + y_0)/B^3; ?)
+       paddq   \c3, \u       // (y_3 + floor((y_2 B^2 + y_1 B + y_0)/B^3; ?)
   .ifnes "\hi", "nil"
        movdqa  \t, \c3
        pxor    \u, \u
   .endif
-       punpckldq \c1, \c3              // (y^*_1, y^*_3, ?, ?)
+       punpckldq \c1, \c3              // (y^*_1, y^*_3; ?, ?)
   .ifnes "\hi", "nil"
        psrlq   \t, 32                  // very high bits of y
        paddq   \hi, \t
        // On exit, the carry registers, including XMM15, are updated to hold
        // C + A; XMM0, XMM1, XMM2, and XMM3 are clobbered.  The other
        // registers are preserved.
-       movd    xmm0, [rdi +  0]        // (a_0, 0)
-       movd    xmm1, [rdi +  4]        // (a_1, 0)
-       movd    xmm2, [rdi +  8]        // (a_2, 0)
-       movd    xmm15, [rdi + 12]       // (a_3, 0)
-       paddq   xmm12, xmm0             // (c'_0 + a_0, c''_0)
-       paddq   xmm13, xmm1             // (c'_1 + a_1, c''_1)
-       paddq   xmm14, xmm2             // (c'_2 + a_2, c''_2 + a_3 b)
+       movd    xmm0, [rdi +  0]        // (a_0; 0)
+       movd    xmm1, [rdi +  4]        // (a_1; 0)
+       movd    xmm2, [rdi +  8]        // (a_2; 0)
+       movd    xmm15, [rdi + 12]       // (a_3; 0)
+       paddq   xmm12, xmm0             // (c'_0 + a_0; c''_0)
+       paddq   xmm13, xmm1             // (c'_1 + a_1; c''_1)
+       paddq   xmm14, xmm2             // (c'_2 + a_2; c''_2 + a_3 b)
 .endm
 
 ///--------------------------------------------------------------------------
@@ -621,8 +619,8 @@ INTFUNC(mmla4)
        mulcore xmm7, 1,   xmm10, xmm11, xmm0,  xmm1,  xmm2
        accum                            xmm4,  xmm5,  xmm6
 
-       punpckldq xmm12, xmm15          // (w_0, 0, w_1, 0)
-       punpckhdq xmm14, xmm15          // (w_2, 0, w_3, 0)
+       punpckldq xmm12, xmm15          // (w_0, 0; w_1, 0)
+       punpckhdq xmm14, xmm15          // (w_2, 0; w_3, 0)
 
        mulcore xmm7, 2,   xmm10, xmm11, xmm0,  xmm1
        accum                            xmm5,  xmm6
@@ -634,10 +632,10 @@ INTFUNC(mmla4)
        mulcore xmm7, 3,   xmm10, xmm11, xmm0
        accum                            xmm6
 
-       punpckldq xmm12, xmm2           // (w_0, 0, 0, 0)
-       punpckldq xmm14, xmm2           // (w_2, 0, 0, 0)
-       punpckhdq xmm13, xmm2           // (w_1, 0, 0, 0)
-       punpckhdq xmm15, xmm2           // (w_3, 0, 0, 0)
+       punpckldq xmm12, xmm2           // (w_0, 0; 0, 0)
+       punpckldq xmm14, xmm2           // (w_2, 0; 0, 0)
+       punpckhdq xmm13, xmm2           // (w_1, 0; 0, 0)
+       punpckhdq xmm15, xmm2           // (w_3, 0; 0, 0)
 
        // That's lots of pieces.  Now we have to assemble the answer.
        squash  xmm3, xmm4, xmm5, xmm6,  xmm0, xmm1,  xmm10
@@ -703,8 +701,8 @@ INTFUNC(mont4)
        mulcore xmm7, 1,   xmm8,  xmm9,  xmm0,  xmm1,  xmm2
        accum                            xmm4,  xmm5,  xmm6
 
-       punpckldq xmm12, xmm15          // (w_0, 0, w_1, 0)
-       punpckhdq xmm14, xmm15          // (w_2, 0, w_3, 0)
+       punpckldq xmm12, xmm15          // (w_0, 0; w_1, 0)
+       punpckhdq xmm14, xmm15          // (w_2, 0; w_3, 0)
 
        mulcore xmm7, 2,   xmm8,  xmm9,  xmm0,  xmm1
        accum                            xmm5,  xmm6
@@ -716,10 +714,10 @@ INTFUNC(mont4)
        mulcore xmm7, 3,   xmm8,  xmm9,  xmm0
        accum                            xmm6
 
-       punpckldq xmm12, xmm2           // (w_0, 0, 0, 0)
-       punpckldq xmm14, xmm2           // (w_2, 0, 0, 0)
-       punpckhdq xmm13, xmm2           // (w_1, 0, 0, 0)
-       punpckhdq xmm15, xmm2           // (w_3, 0, 0, 0)
+       punpckldq xmm12, xmm2           // (w_0, 0; 0, 0)
+       punpckldq xmm14, xmm2           // (w_2, 0; 0, 0)
+       punpckhdq xmm13, xmm2           // (w_1, 0; 0, 0)
+       punpckhdq xmm15, xmm2           // (w_3, 0; 0, 0)
 
        // That's lots of pieces.  Now we have to assemble the answer.
        squash  xmm3, xmm4, xmm5, xmm6,  xmm0, xmm1,  xmm10
@@ -752,6 +750,13 @@ ENDFUNC
 ///--------------------------------------------------------------------------
 /// Bulk multipliers.
 
+FUNC(mpx_umul4_amd64_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       .arch   pentium4
+ENDFUNC
+
 FUNC(mpx_umul4_amd64_sse2)
        // void mpx_umul4_amd64_sse2(mpw *dv, const mpw *av, const mpw *avl,
        //                         const mpw *bv, const mpw *bvl);
@@ -901,6 +906,13 @@ FUNC(mpx_umul4_amd64_sse2)
 
 ENDFUNC
 
+FUNC(mpxmont_mul4_amd64_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       .arch   pentium4
+ENDFUNC
+
 FUNC(mpxmont_mul4_amd64_sse2)
        // void mpxmont_mul4_amd64_sse2(mpw *dv, const mpw *av, const mpw *bv,
        //                           const mpw *nv, size_t n, const mpw *mi);
@@ -1095,6 +1107,13 @@ FUNC(mpxmont_mul4_amd64_sse2)
 
 ENDFUNC
 
+FUNC(mpxmont_redc4_amd64_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       .arch   pentium4
+ENDFUNC
+
 FUNC(mpxmont_redc4_amd64_sse2)
        // void mpxmont_redc4_amd64_sse2(mpw *dv, mpw *dvl, const mpw *nv,
        //                             size_t n, const mpw *mi);
@@ -1474,9 +1493,9 @@ ENDFUNC
 .endm
 
 .macro testldcarry
-       movdqu  xmm12, [rcx +  0]       // (c'_0, c''_0)
-       movdqu  xmm13, [rcx + 16]       // (c'_1, c''_1)
-       movdqu  xmm14, [rcx + 32]       // (c'_2, c''_2)
+       movdqu  xmm12, [rcx +  0]       // (c'_0; c''_0)
+       movdqu  xmm13, [rcx + 16]       // (c'_1; c''_1)
+       movdqu  xmm14, [rcx + 32]       // (c'_2; c''_2)
 .endm
 
 .macro testtop u=nil
index baf7cc5..904c0d0 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
-///--------------------------------------------------------------------------
-/// Prologue.
-
        .arch   pentium4
+
        .text
 
 ///--------------------------------------------------------------------------
 .macro mulcore r, s, d0, d1=nil, d2=nil, d3=nil
        // Load a word r_i from R, multiply by the expanded operand [S], and
        // leave the pieces of the product in registers D0, D1, D2, D3.
-       movd    \d0, \r                 // (r_i, 0, 0, 0)
+       movd    \d0, \r                 // (r_i, 0; 0, 0)
   .ifnes "\d1", "nil"
-       movdqa  \d1, [\s]               // (s'_0, s'_1, s''_0, s''_1)
+       movdqa  \d1, [\s]               // (s'_0, s'_1; s''_0, s''_1)
   .endif
   .ifnes "\d3", "nil"
-       movdqa  \d3, [\s + 16]          // (s'_2, s'_3, s''_2, s''_3)
+       movdqa  \d3, [\s + 16]          // (s'_2, s'_3; s''_2, s''_3)
   .endif
-       pshufd  \d0, \d0, SHUF(3, 0, 3, 0) // (r_i, ?, r_i, ?)
+       pshufd  \d0, \d0, SHUF(0, 3, 0, 3) // (r_i, ?; r_i, ?)
   .ifnes "\d1", "nil"
-       psrldq  \d1, 4                  // (s'_1, s''_0, s''_1, 0)
+       psrldq  \d1, 4                  // (s'_1, s''_0; s''_1, 0)
   .endif
   .ifnes "\d2", "nil"
     .ifnes "\d3", "nil"
-       movdqa  \d2, \d3                // another copy of (s'_2, s'_3, ...)
+       movdqa  \d2, \d3                // another copy of (s'_2, s'_3; ...)
     .else
-       movdqa  \d2, \d0                // another copy of (r_i, ?, r_i, ?)
+       movdqa  \d2, \d0                // another copy of (r_i, ?; r_i, ?)
     .endif
   .endif
   .ifnes "\d3", "nil"
-       psrldq  \d3, 4                  // (s'_3, s''_2, s''_3, 0)
+       psrldq  \d3, 4                  // (s'_3, s''_2; s''_3, 0)
   .endif
   .ifnes "\d1", "nil"
-       pmuludq \d1, \d0                // (r_i s'_1, r_i s''_1)
+       pmuludq \d1, \d0                // (r_i s'_1; r_i s''_1)
   .endif
   .ifnes "\d3", "nil"
-       pmuludq \d3, \d0                // (r_i s'_3, r_i s''_3)
+       pmuludq \d3, \d0                // (r_i s'_3; r_i s''_3)
   .endif
   .ifnes "\d2", "nil"
     .ifnes "\d3", "nil"
-       pmuludq \d2, \d0                // (r_i s'_2, r_i s''_2)
+       pmuludq \d2, \d0                // (r_i s'_2; r_i s''_2)
     .else
        pmuludq \d2, [\s + 16]
     .endif
   .endif
-       pmuludq \d0, [\s]               // (r_i s'_0, r_i s''_0)
+       pmuludq \d0, [\s]               // (r_i s'_0; r_i s''_0)
 .endm
 
 .macro accum   c0, c1=nil, c2=nil, c3=nil
        // carry registers.  On completion, XMM3 is clobbered.  If CC is
        // `nil', then the contribution which would have been added to it is
        // left in C.
-       pshufd  xmm3, \c, SHUF(2, 3, 3, 3) // (?, ?, ?, t = c'' mod B)
-       psrldq  xmm3, 12                // (t, 0, 0, 0) = (t, 0)
-       pslldq  xmm3, 2                 // (t b, 0)
-       paddq   \c, xmm3                // (c' + t b, c'')
+       pshufd  xmm3, \c, SHUF(3, 3, 3, 2) // (?, ?; ?, t = c'' mod B)
+       psrldq  xmm3, 12                // (t, 0; 0, 0) = (t, 0)
+       pslldq  xmm3, 2                 // (t b; 0)
+       paddq   \c, xmm3                // (c' + t b; c'')
        movd    \d, \c
        psrlq   \c, 32                  // floor(c/B)
   .ifnes "\cc", "nil"
        // of the value represented in C are written to D, and the remaining
        // bits are left at the bottom of T.
        movdqa  \t, \c
-       psllq   \t, 16                  // (?, c'' b)
-       pslldq  \c, 8                   // (0, c')
-       paddq   \t, \c                  // (?, c' + c'' b)
-       psrldq  \t, 8                   // c' + c'' b
+       psllq   \t, 16                  // (?; c'' b)
+       pslldq  \c, 8                   // (0; c')
+       paddq   \t, \c                  // (?; c' + c'' b)
+       psrldq  \t, 8                   // (c' + c'' b; 0) = (c; 0)
        movd    \d, \t
-       psrldq  \t, 4                   // floor((c' + c'' b)/B)
+       psrldq  \t, 4                   // (floor(c/B); 0)
 .endm
 
 .macro expand  z, a, b, c=nil, d=nil
        // On entry, A and C hold packed 128-bit values, and Z is zero.  On
        // exit, A:B and C:D together hold the same values in expanded
        // form.  If C is `nil', then only expand A to A:B.
-       movdqa  \b, \a                  // (a_0, a_1, a_2, a_3)
+       movdqa  \b, \a                  // (a_0, a_1; a_2, a_3)
   .ifnes "\c", "nil"
-       movdqa  \d, \c                  // (c_0, c_1, c_2, c_3)
+       movdqa  \d, \c                  // (c_0, c_1; c_2, c_3)
   .endif
-       punpcklwd \a, \z                // (a'_0, a''_0, a'_1, a''_1)
-       punpckhwd \b, \z                // (a'_2, a''_2, a'_3, a''_3)
+       punpcklwd \a, \z                // (a'_0, a''_0; a'_1, a''_1)
+       punpckhwd \b, \z                // (a'_2, a''_2; a'_3, a''_3)
   .ifnes "\c", "nil"
-       punpcklwd \c, \z                // (c'_0, c''_0, c'_1, c''_1)
-       punpckhwd \d, \z                // (c'_2, c''_2, c'_3, c''_3)
+       punpcklwd \c, \z                // (c'_0, c''_0; c'_1, c''_1)
+       punpckhwd \d, \z                // (c'_2, c''_2; c'_3, c''_3)
   .endif
-       pshufd  \a, \a, SHUF(3, 1, 2, 0) // (a'_0, a'_1, a''_0, a''_1)
-       pshufd  \b, \b, SHUF(3, 1, 2, 0) // (a'_2, a'_3, a''_2, a''_3)
+       pshufd  \a, \a, SHUF(0, 2, 1, 3) // (a'_0, a'_1; a''_0, a''_1)
+       pshufd  \b, \b, SHUF(0, 2, 1, 3) // (a'_2, a'_3; a''_2, a''_3)
   .ifnes "\c", "nil"
-       pshufd  \c, \c, SHUF(3, 1, 2, 0) // (c'_0, c'_1, c''_0, c''_1)
-       pshufd  \d, \d, SHUF(3, 1, 2, 0) // (c'_2, c'_3, c''_2, c''_3)
+       pshufd  \c, \c, SHUF(0, 2, 1, 3) // (c'_0, c'_1; c''_0, c''_1)
+       pshufd  \d, \d, SHUF(0, 2, 1, 3) // (c'_2, c'_3; c''_2, c''_3)
   .endif
 .endm
 
        // we can do that, we must gather them together.
        movdqa  \t, \c0
        movdqa  \u, \c1
-       punpcklqdq \t, \c2              // (y'_0, y'_2)
-       punpckhqdq \c0, \c2             // (y''_0, y''_2)
-       punpcklqdq \u, \c3              // (y'_1, y'_3)
-       punpckhqdq \c1, \c3             // (y''_1, y''_3)
+       punpcklqdq \t, \c2              // (y'_0; y'_2)
+       punpckhqdq \c0, \c2             // (y''_0; y''_2)
+       punpcklqdq \u, \c3              // (y'_1; y'_3)
+       punpckhqdq \c1, \c3             // (y''_1; y''_3)
 
        // Now split the double-prime pieces.  The high (up to) 48 bits will
        // go up; the low 16 bits go down.
        movdqa  \c3, \c1
        psllq   \c2, 48
        psllq   \c3, 48
-       psrlq   \c0, 16                 // high parts of (y''_0, y''_2)
-       psrlq   \c1, 16                 // high parts of (y''_1, y''_3)
-       psrlq   \c2, 32                 // low parts of (y''_0, y''_2)
-       psrlq   \c3, 32                 // low parts of (y''_1, y''_3)
+       psrlq   \c0, 16                 // high parts of (y''_0; y''_2)
+       psrlq   \c1, 16                 // high parts of (y''_1; y''_3)
+       psrlq   \c2, 32                 // low parts of (y''_0; y''_2)
+       psrlq   \c3, 32                 // low parts of (y''_1; y''_3)
   .ifnes "\hi", "nil"
        movdqa  \hi, \c1
   .endif
-       pslldq  \c1, 8                  // high part of (0, y''_1)
+       pslldq  \c1, 8                  // high part of (0; y''_1)
 
        paddq   \t, \c2                 // propagate down
        paddq   \u, \c3
-       paddq   \t, \c1                 // and up: (y_0, y_2)
-       paddq   \u, \c0                 // (y_1, y_3)
+       paddq   \t, \c1                 // and up: (y_0; y_2)
+       paddq   \u, \c0                 // (y_1; y_3)
   .ifnes "\hi", "nil"
-       psrldq  \hi, 8                  // high part of (y''_3, 0)
+       psrldq  \hi, 8                  // high part of (y''_3; 0)
   .endif
 
        // Finally extract the answer.  This complicated dance is better than
        // storing to memory and loading, because the piecemeal stores
        // inhibit store forwarding.
-       movdqa  \c3, \t                 // (y_0, y_1)
-       movdqa  \lo, \t                 // (y^*_0, ?, ?, ?)
-       psrldq  \t, 8                   // (y_2, 0)
-       psrlq   \c3, 32                 // (floor(y_0/B), ?)
-       paddq   \c3, \u                 // (y_1 + floor(y_0/B), ?)
-       movdqa  \c1, \c3                // (y^*_1, ?, ?, ?)
-       psrldq  \u, 8                   // (y_3, 0)
-       psrlq   \c3, 32                 // (floor((y_1 B + y_0)/B^2, ?)
-       paddq   \c3, \t                 // (y_2 + floor((y_1 B + y_0)/B^2, ?)
-       punpckldq \lo, \c3              // (y^*_0, y^*_2, ?, ?)
-       psrlq   \c3, 32             // (floor((y_2 B^2 + y_1 B + y_0)/B^3, ?)
-       paddq   \c3, \u       // (y_3 + floor((y_2 B^2 + y_1 B + y_0)/B^3, ?)
+       movdqa  \c3, \t                 // (y_0; ?)
+       movdqa  \lo, \t                 // (y^*_0, ?; ?, ?)
+       psrldq  \t, 8                   // (y_2; 0)
+       psrlq   \c3, 32                 // (floor(y_0/B); ?)
+       paddq   \c3, \u                 // (y_1 + floor(y_0/B); ?)
+       movdqa  \c1, \c3                // (y^*_1, ?; ?, ?)
+       psrldq  \u, 8                   // (y_3; 0)
+       psrlq   \c3, 32                 // (floor((y_1 B + y_0)/B^2; ?)
+       paddq   \c3, \t                 // (y_2 + floor((y_1 B + y_0)/B^2; ?)
+       punpckldq \lo, \c3              // (y^*_0, y^*_2; ?, ?)
+       psrlq   \c3, 32             // (floor((y_2 B^2 + y_1 B + y_0)/B^3; ?)
+       paddq   \c3, \u       // (y_3 + floor((y_2 B^2 + y_1 B + y_0)/B^3; ?)
   .ifnes "\hi", "nil"
        movdqa  \t, \c3
        pxor    \u, \u
   .endif
-       punpckldq \c1, \c3              // (y^*_1, y^*_3, ?, ?)
+       punpckldq \c1, \c3              // (y^*_1, y^*_3; ?, ?)
   .ifnes "\hi", "nil"
        psrlq   \t, 32                  // very high bits of y
        paddq   \hi, \t
        // On exit, the carry registers, including XMM7, are updated to hold
        // C + A; XMM0, XMM1, XMM2, and XMM3 are clobbered.  The other
        // registers are preserved.
-       movd    xmm0, [edi +  0]        // (a_0, 0)
-       movd    xmm1, [edi +  4]        // (a_1, 0)
-       movd    xmm2, [edi +  8]        // (a_2, 0)
-       movd    xmm7, [edi + 12]        // (a_3, 0)
-
-       paddq   xmm4, xmm0              // (c'_0 + a_0, c''_0)
-       paddq   xmm5, xmm1              // (c'_1 + a_1, c''_1)
-       paddq   xmm6, xmm2              // (c'_2 + a_2, c''_2 + a_3 b)
+       movd    xmm0, [edi +  0]        // (a_0; 0)
+       movd    xmm1, [edi +  4]        // (a_1; 0)
+       movd    xmm2, [edi +  8]        // (a_2; 0)
+       movd    xmm7, [edi + 12]        // (a_3; 0)
+
+       paddq   xmm4, xmm0              // (c'_0 + a_0; c''_0)
+       paddq   xmm5, xmm1              // (c'_1 + a_1; c''_1)
+       paddq   xmm6, xmm2              // (c'_2 + a_2; c''_2 + a_3 b)
 .endm
 
 ///--------------------------------------------------------------------------
@@ -678,6 +676,14 @@ ENDFUNC
 ///--------------------------------------------------------------------------
 /// Bulk multipliers.
 
+FUNC(mpx_umul4_x86_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       // and drop through...
+       .arch   pentium4
+ENDFUNC
+
 FUNC(mpx_umul4_x86_sse2)
        // void mpx_umul4_x86_sse2(mpw *dv, const mpw *av, const mpw *avl,
        //                         const mpw *bv, const mpw *bvl);
@@ -699,7 +705,7 @@ FUNC(mpx_umul4_x86_sse2)
        pushreg ebx
        pushreg esi
        pushreg edi
-       setfp   ebp
+       setfp
        and     esp, ~15
        sub     esp, 32
   endprologue
@@ -778,6 +784,14 @@ FUNC(mpx_umul4_x86_sse2)
 
 ENDFUNC
 
+FUNC(mpxmont_mul4_x86_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       // and drop through...
+       .arch   pentium4
+ENDFUNC
+
 FUNC(mpxmont_mul4_x86_sse2)
        // void mpxmont_mul4_x86_sse2(mpw *dv, const mpw *av, const mpw *bv,
        //                           const mpw *nv, size_t n, const mpw *mi);
@@ -806,7 +820,7 @@ FUNC(mpxmont_mul4_x86_sse2)
        pushreg ebx
        pushreg esi
        pushreg edi
-       setfp   ebp
+       setfp
        and     esp, ~15
        sub     esp, 112
   endprologue
@@ -919,6 +933,14 @@ FUNC(mpxmont_mul4_x86_sse2)
 
 ENDFUNC
 
+FUNC(mpxmont_redc4_x86_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       // and drop through...
+       .arch   pentium4
+ENDFUNC
+
 FUNC(mpxmont_redc4_x86_sse2)
        // void mpxmont_redc4_x86_sse2(mpw *dv, mpw *dvl, const mpw *nv,
        //                             size_t n, const mpw *mi);
@@ -944,7 +966,7 @@ FUNC(mpxmont_redc4_x86_sse2)
        pushreg ebx
        pushreg esi
        pushreg edi
-       setfp   ebp
+       setfp
        and     esp, ~15
        sub     esp, 76
   endprologue
@@ -1073,7 +1095,7 @@ ENDFUNC
        pushreg ebx
        pushreg esi
        pushreg edi
-       setfp   ebp
+       setfp
        and     esp, ~15
        sub     esp, 3*32 + 4*4
   endprologue
@@ -1098,9 +1120,9 @@ ENDFUNC
 
 .macro testldcarry c
        mov     ecx, \c                 // -> c
-       movdqu  xmm4, [ecx +  0]        // (c'_0, c''_0)
-       movdqu  xmm5, [ecx + 16]        // (c'_1, c''_1)
-       movdqu  xmm6, [ecx + 32]        // (c'_2, c''_2)
+       movdqu  xmm4, [ecx +  0]        // (c'_0; c''_0)
+       movdqu  xmm5, [ecx + 16]        // (c'_1; c''_1)
+       movdqu  xmm6, [ecx + 32]        // (c'_2; c''_2)
 .endm
 
 .macro testexpand v=nil, y=nil
index 3983e7c..4294845 100644 (file)
@@ -923,19 +923,25 @@ static void simple_umul(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl,
 
 #if CPUFAM_X86
   MAYBE_UMUL4(x86_sse2)
+  MAYBE_UMUL4(x86_avx)
 #endif
 
 #if CPUFAM_AMD64
   MAYBE_UMUL4(amd64_sse2)
+  MAYBE_UMUL4(amd64_avx)
 #endif
 
 static mpx_umul__functype *pick_umul(void)
 {
 #if CPUFAM_X86
+  DISPATCH_PICK_COND(mpx_umul, maybe_umul4_x86_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(mpx_umul, maybe_umul4_x86_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
 #if CPUFAM_AMD64
+  DISPATCH_PICK_COND(mpx_umul, maybe_umul4_amd64_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(mpx_umul, maybe_umul4_amd64_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
diff --git a/math/pgen-granfrob.c b/math/pgen-granfrob.c
new file mode 100644 (file)
index 0000000..98c8f8c
--- /dev/null
@@ -0,0 +1,276 @@
+/* -*-c-*-
+ *
+ * Grantham's Frobenius primality test
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "mp.h"
+#include "mpmont.h"
+#include "mpscan.h"
+#include "pgen.h"
+
+#include "mptext.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+static int squarep(mp *n)
+{
+  mp *t = MP_NEW;
+  int rc;
+
+  if (MP_NEGP(n)) return (0);
+  t = mp_sqrt(t, n); t = mp_sqr(t, t);
+  rc = MP_EQ(t, n); mp_drop(t); return (rc);
+}
+
+/* --- @pgen_granfrob@ --- *
+ *
+ * Arguments:  @mp *n@ = an integer to test
+ *             @int a, b@ = coefficients; if @a@ is zero then choose
+ *                     automatically
+ *
+ * Returns:    One of the @PGEN_...@ codes.
+ *
+ * Use:                Performs a quadratic version of Grantham's Frobenius
+ *             primality test, which is a simple extension of the standard
+ *             Lucas test.
+ *
+ *             If %$a^2 - 4 b$% is a perfect square then the test can't
+ *             work; this function returns @PGEN_ABORT@ under these
+ *             circumstances.
+ */
+
+int pgen_granfrob(mp *n, int a, int b)
+{
+  mp *v = MP_NEW, *w = MP_NEW, *aa = MP_NEW, *bb = MP_NEW, *bi = MP_NEW,
+    *k = MP_NEW, *x = MP_NEW, *y = MP_NEW, *z = MP_NEW, *t, *u;
+  mp ma; mpw wa;
+  mp mb; mpw wb;
+  mp md; mpw wd; int d;
+  mpmont mm;
+  mpscan msc;
+  int e, bit, rc;
+
+  /* Maybe this is a no-hoper. */
+  if (MP_NEGP(n)) return (PGEN_FAIL);
+  if (MP_EQ(n, MP_TWO)) return (PGEN_DONE);
+  if (!MP_ODDP(n)) return (PGEN_FAIL);
+
+  /* First, build the parameters as large integers. */
+  mp_build(&ma, &wa, &wa + 1); mp_build(&mb, &wb, &wb + 1);
+  mp_build(&md, &wd, &wd + 1);
+  mpmont_create(&mm, n);
+
+  /* Prepare the Lucas sequence parameters.  Here, %$\Delta$% is the
+   * disciminant of the polynomial %$p(x) = x^2 - a x + b$%, i.e.,
+   * %$\Delta = a^2 - 4 b$%.
+   */
+  if (a) {
+    /* Explicit parameters.  Just set them and check that they'll work. */
+
+    if (a >= 0) wa = a; else { wa = -a; ma.f |= MP_NEG; }
+    if (b >= 0) wb = b; else { wb = -b; mb.f |= MP_NEG; }
+    d = a*a - 4*b;
+    if (d >= 0) wd = d; else { wd = -d; md.f |= MP_NEG; }
+
+    /* Determine the quadratic character of %$\Delta$%.  If %$(\Delta | n)$%
+     * is zero then we'll have a problem, but we'll catch that case with the
+     * GCD check below.
+     */
+    e = mp_jacobi(&md, n);
+
+    /* If %$\Delta$% is a perfect square then the test can't work. */
+    if (e == 1 && squarep(&md)) { rc = PGEN_ABORT; goto end; }
+  } else {
+    /* Determine parameters.  Use Selfridge's `Method A': choose the first
+     * %$\Delta$% from the sequence %$5$%, %$-7$%, %%\dots%%, such that
+     * %$(\Delta | n) = -1$%.
+     */
+
+    wa = 1; wd = 5;
+    for (;;) {
+      e = mp_jacobi(&md, n); if (e != +1) break;
+      if (wd == 25 && squarep(n)) { rc = PGEN_FAIL; goto end; }
+      wd += 2; md.f ^= MP_NEG;
+    }
+    a = 1; d = wd;
+    if (md.f&MP_NEG) { wb = (wd + 1)/4; d = -d; }
+    else { wb = (wd - 1)/4; mb.f |= MP_NEG; }
+    b = (1 - d)/4;
+  }
+
+  /* The test won't work if %$\gcd(2 a b \Delta, n) \ne 1$%. */
+  x = mp_lsl(x, &ma, 1); x = mp_mul(x, x, &mb); x = mp_mul(x, x, &md);
+  mp_gcd(&y, 0, 0, x, n);
+  if (!MP_EQ(y, MP_ONE))
+    { rc = MP_EQ(y, n) ? PGEN_ABORT : PGEN_FAIL; goto end; }
+
+  /* Now we use binary a Lucas chain to evaluate %$V_{n-e}(a, b) \pmod{n}$%.
+   * Here,
+   *
+   *   * %$U_{i+1}(a, b) = a U_i(a, b) - b U_{i-1}(a, b)$%, and
+   *   * %$V_{i+1}(a, b) = a V_i(a, b) - b V_{i-1}(a, b)$%; with
+   *   * %$U_0(a, b) = 0$%, $%U_1(a, b) = 1$%, %$V_0(a, b) = 2$%, and
+   *     %$V_1(a, b) = a$%.
+   *
+   * To compute this, we use the handy identities
+   *
+   *   %$V_{i+j}(a, b) = V_i(a, b) V_j(a, b) - b^i V_{j-i}(a, b)$%
+   *
+   * and
+   *
+   *   %$U_i(a, b) = (2 V_{i+1}(a, b) - a V_i(a, b))/\Delta$%.
+   *
+   * Let %$k = n - e$%.  Given %$V_i(a, b)$% and %$V_{i+1}(a, b)$%, we can
+   * determine either %$V_{2i}(a, b)$% and %$V_{2i+1}(a, b)$%, or
+   * %$V_{2i+1}(a, b)$% and %$V_{2i+2}(a, b)$%.
+   *
+   * To do this, suppose that %$n < 2^\ell$% and %$0 \le i \le \ell%; we'll
+   * start with %$i = 0$%.  Divide %$n = n_i 2^{\ell-i} + n'_i$% with
+   * %$n'_i < 2^{\ell-i}$%.  To do this, we maintain %$v_i = V_{n_i}(a, b)$%,
+   * %$w_i = V_{n_i+1}(a, b)$%, and %$b_i = b^{n_i}$%, all modulo %$n$%.  If
+   * %$n'_i < 2^{\ell-i-1}$% then we have %$n'_{i+1} = n'_i$% and
+   * %$n_{i+i} = 2 n_i$%; otherwise %$n'_{i+1} = n'_i - 2^{\ell-i-1}$% and
+   * %$n_{i+i} = 2 n_i + 1$%.
+   */
+  k = mp_add(k, n, e > 0 ? MP_MONE : MP_ONE);
+  aa = mpmont_mul(&mm, aa, &ma, mm.r2);
+  bb = mpmont_mul(&mm, bb, &mb, mm.r2); bi = MP_COPY(mm.r);
+  v = mpmont_mul(&mm, v, MP_TWO, mm.r2); w = MP_COPY(aa);
+
+  for (mpscan_rinitx(&msc, k->v, k->vl); mpscan_rstep(&msc); ) {
+    bit = mpscan_rbit(&msc);
+
+    /* We will want %$x = V_{n_i+1}(a, b) = V_{n_i} V_{n_i+1} - a b^{n_i}$%,
+     * but we don't yet know whether this is %$v_{i+1}$% or %$w_{i+1}$%.
+     */
+    x = mpmont_mul(&mm, x, v, w);
+    if (a == 1) x = mp_sub(x, x, bi);
+    else { y = mpmont_mul(&mm, y, aa, bi); x = mp_sub(x, x, y); }
+    if (MP_NEGP(x)) x = mp_add(x, x, n);
+
+    if (!bit) {
+      /* We're in the former case: %$n_{i+i} = 2 n_i$%.  So %$w_{i+1} = x$%,
+       * %$v_{i+1} = (v_i^2 - 2 b_i$%, and %$b_{i+1} = b_i^2$%.
+       */
+
+      y = mp_sqr(y, v); y = mpmont_reduce(&mm, y, y);
+      y = mp_sub(y, y, bi); if (MP_NEGP(y)) y = mp_add(y, y, n);
+      y = mp_sub(y, y, bi); if (MP_NEGP(y)) y = mp_add(y, y, n);
+      bi = mp_sqr(bi, bi); bi = mpmont_reduce(&mm, bi, bi);
+      t = v; u = w; v = y; w = x; x = t; y = u;
+    } else {
+      /* We're in the former case: %$n_{i+i} = 2 n_i + 1$%.  So
+       * %$v_{i+1} = x$%, %$w_{i+1} = w_i^2 - 2 b b^i$%$%, and
+       * %$b_{i+1} = b b_i^2$%.
+       */
+
+      y = mp_sqr(y, w); y = mpmont_reduce(&mm, y, y);
+      z = mpmont_mul(&mm, z, bi, bb);
+      y = mp_sub(y, y, z); if (MP_NEGP(y)) y = mp_add(y, y, n);
+      y = mp_sub(y, y, z); if (MP_NEGP(y)) y = mp_add(y, y, n);
+      bi = mpmont_mul(&mm, bi, bi, z);
+      t = v; u = w; v = x; w = y; x = t; y = u;
+    }
+  }
+
+  /* The Lucas test is that %$U_k(a, b) \equiv 0 \pmod{n}$% if %$n$% is
+   * prime.  I'm assured that
+   *
+   *   %$U_k(a, b) = (2 V_{k+1}(a, b) - a V_k(a, b))/\Delta$%
+   *
+   * so this is just a matter of checking that %$2 w - a v \equiv 0$%.
+   */
+  x = mp_add(x, w, w); y = mp_sub(y, x, n);
+  if (!MP_NEGP(y)) { t = x; x = y; y = t; }
+  if (a == 1) x = mp_sub(x, x, v);
+  else { y = mpmont_mul(&mm, y, v, aa); x = mp_sub(x, x, y); }
+  if (MP_NEGP(x)) x = mp_add(x, x, n);
+  if (!MP_ZEROP(x)) { rc = PGEN_FAIL; goto end; }
+
+  /* Grantham's Frobenius test is that, also, %$V_k(a, b) v = \equiv 2 b$%
+   * if %$n$% is prime and %$(\Delta | n) = -1$%, or %$v \equiv 2$% if
+   * %$(\Delta | n) = +1$%.
+   */
+  if (MP_ODDP(v)) v = mp_add(v, v, n);
+  v = mp_lsr(v, v, 1);
+  if (!MP_EQ(v, e == +1 ? mm.r : bb)) { rc = PGEN_FAIL; goto end; }
+
+  /* Looks like we made it. */
+  rc = PGEN_PASS;
+end:
+  mp_drop(v); mp_drop(w); mp_drop(aa); mp_drop(bb); mp_drop(bi);
+  mp_drop(k); mp_drop(x); mp_drop(y); mp_drop(z);
+  mpmont_destroy(&mm);
+  return (rc);
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/testrig.h>
+
+#include "mptext.h"
+
+static int verify(dstr *v)
+{
+  mp *n = *(mp **)v[0].buf;
+  int a = *(int *)v[1].buf, b = *(int *)v[2].buf, xrc = *(int *)v[3].buf, rc;
+  int ok = 1;
+
+  rc = pgen_granfrob(n, a, b);
+  if (rc != xrc) {
+    fputs("\n*** pgen_granfrob failed", stdout);
+    fputs("\nn = ", stdout); mp_writefile(n, stdout, 10);
+    printf("\na = %d", a);
+    printf("\nb = %d", a);
+    printf("\nexp rc = %d", xrc);
+    printf("\ncalc rc = %d\n", rc);
+    ok = 0;
+  }
+
+  mp_drop(n);
+  assert(mparena_count(MPARENA_GLOBAL) == 0);
+  return (ok);
+}
+
+static test_chunk tests[] = {
+  { "pgen-granfrob", verify,
+    { &type_mp, &type_int, &type_int, &type_int, 0 } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  sub_init();
+  test_run(argc, argv, tests, SRCDIR "/t/pgen");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
index 84185e3..f060659 100644 (file)
@@ -319,28 +319,33 @@ mp *pgen(const char *name, mp *d, mp *m, pgen_proc *event, void *ectx,
  *             @grand *gr@ = a random number source
  *
  * Returns:    Nonzero if @p@ is really prime.
+ *
+ * Use:                Checks the primality of @p@.  If @p@ is prime, then this
+ *             function returns nonzero; if @p@ is really composite then it
+ *             %%\emph{probably}%% returns zero, but might not.
+ *
+ *             Currently, this function uses the Baillie--PSW test, which
+ *             combines a single Miller--Rabin test with witness 2 with a
+ *             single Frobenius test with parameters chosen using
+ *             Selfridge's `Method A'.  No composites are known which pass
+ *             this test, though it's conjectured that infinitely many
+ *             exist.
  */
 
 int pgen_primep(mp *p, grand *gr)
 {
-  int i;
   rabin r;
-  mp *x = MP_NEW;
+  int rc;
 
   if (MP_NEGP(p)) return (0);
   switch (pfilt_smallfactor(p)) {
     case PGEN_DONE: return (1);
     case PGEN_FAIL: return (0);
   }
-  rabin_create(&r, p);
-  for (i = 32; i; i--) {
-    x = mprand_range(x, p, gr, 0);
-    if (rabin_rtest(&r, x) == PGEN_FAIL)
-      break;
-  }
-  MP_DROP(x);
-  rabin_destroy(&r);
-  return (!i);
+  rabin_create(&r, p); rc = rabin_test(&r, MP_TWO); rabin_destroy(&r);
+  if (rc == PGEN_FAIL) return (0);
+  rc = pgen_granfrob(p, 0, 0); if (rc == PGEN_FAIL) return (0);
+  return (1);
 }
 
 /*----- Test rig ----------------------------------------------------------*/
index b103c30..eef9141 100644 (file)
@@ -270,6 +270,29 @@ extern mp *pgen(const char */*name*/, mp */*d*/, mp */*m*/,
                unsigned /*steps*/, pgen_proc */*step*/, void */*sctx*/,
                unsigned /*tests*/, pgen_proc */*test*/, void */*tctx*/);
 
+/* --- @pgen_granfrob@ --- *
+ *
+ * Arguments:  @mp *n@ = an integer to test
+ *             @int a, b@ = coefficients; if @a@ is zero then choose
+ *                     automatically
+ *
+ * Returns:    One of the @PGEN_...@ codes.
+ *
+ * Use:                Performs a quadratic version of Grantham's Frobenius
+ *             primality test, which is a simple extension of the standard
+ *             Lucas test.
+ *
+ *             If %$a^2 - 4 b$% is a perfect square then the test can't
+ *             work; this function returns @PGEN_ABORT@ under these
+ *             circumstances.
+ *
+ *             If @a@ is zero on entry, then the function will choose
+ *             suitable parameters deterministically -- i.e., it always
+ *             chooses the same parameters for a given %$n$%.
+ */
+
+extern int pgen_granfrob(mp */*n*/, int /*a*/, int /*b*/);
+
 /* --- @pgen_primep@ --- *
  *
  * Arguments:  @mp *p@ = a number to check
index 8d52d19..be26c18 100644 (file)
@@ -14,6 +14,29 @@ pgen {
   166359567317705838255275971708060308423814413741683015010175247351623188739655446196925981468626681882384215574706593049022467680136399439302347043107836749816290369600677730213469006507173065402294688841278559283358390567733443050775707749725690534182003442070447739085348456478911335969765393755383551520173 166359567317705838255275971708060308423814413741683015010175247351623188739655446196925981468626681882384215574706593049022467680136399439302347043107836749816290369600677730213469006507173065402294688841278559283358390567733443050775707749725690534182003442070447739085348456478911335969765393755383551520257;
 }
 
+pgen-granfrob {
+  5 0 0 -1;
+  7 0 0 4;
+  15 0 0 3;
+  5777 1 -1 4; # pseudoprime
+  40301809 0 0 4;
+  86059163416987297647409667483582114939806237974424324409828198660056356336227 1 5 4;
+  102508420970861015999300753620309481186457893679971500520427161277511389396803 1 5 4;
+  72291866454056552194087337607224612505157525245486245416393486917859196707519 1 5 4;
+  72291866454056552194087337607224612505157525245486265416393486917859196707519 1 5 3;
+
+  ## A large Frobenius pseudoprime: call the first number p_1; then p_2 = 31
+  ## (p_1 + 1) - 1 and p_3 = 43 (p_1 + 1) - 1.  These three are all prime.
+  ## Their product is a strong Lucas, and Frobenius, pseudoprime.
+  ##
+  ## See `Prime and Prejudice' by Martin R. Albrecht, Jake Massimo, Kenneth
+  ## G. Paterson, and Juraj Somorovsky.
+  3690125385954346893658786222051913500627130245213169388019826598097107079718295481926241398412699320815932808015860263240282855670239765686869973444864115322609857375876438922226372746215468824202413623127 0 0 4;
+  114393886964584753703422372883609318519441037601608251028614624541010319471267159939713483350793678945293917048491668160448768525777432736292969176790787575000905578652169606589017555132679533550274822316967 0 0 4;
+  158675391596036916427327807548232280526966600544166283684852543718175604427886705722828380131746070795085110744681991319332162793820309924535408858129156958872223867162686873655734028087265159440703785794503 0 0 4;
+  66981291792500223036804182765508448534715465524671325885174850970812009004775815201151227900130153990294748113034471984909912807896550069799856170439734910206802409847773026240559371480115711600866989845251707737806461503879250232804362190067578216069266197879151809743235261582813331022213587929425243163096486125825510076936556242805690400001899138503900919499414951069309064408305196756524628693684938044145785145327821174180933033293089394794328963673467918652042794300291355500468079109432376296868174257674548727592142782202898031102246775544402811199608266683925072825828225074019194302318324623049819212337927 0 0 4;
+}
+
 primep {
   -5 0;
   -1 0;
@@ -24,6 +47,30 @@ primep {
   4 0;
   40301809 1;
   40301811 0;
+
+  ## A small Lucas pseudoprime: 5777 = 53*109.
+  5777 0;
+
+  ## A large strong pseudoprime: this is the product of
+  ##
+  ##   p_1 = 142445387161415482404826365418175962266689133006163
+  ##   p_2 = 5840260873618034778597880982145214452934254453252643
+  ##   p_3 = 14386984103302963722887462907235772188935602433622363
+  ##
+  ## See `Prime and Prejudice' by Martin R. Albrecht, Jake Massimo, Kenneth
+  ## G. Paterson, and Juraj Somorovsky.
+  142445387161415482404826365418175962266689133006163 1;
+  5840260873618034778597880982145214452934254453252643 1;
+  14386984103302963722887462907235772188935602433622363 1;
+  11968794224604718293549908104759518204343930652759288592987578098131927050572705181539873293848476235393230314654912729920657864630317971562727057595285667 0;
+
+  ## A large Lucas pseudoprime: call the first number p_1; then p_2 = 31 (p_1
+  ## + 1) - 1 and p_3 = 43 (p_1 + 1) - 1.  These three are all prime.  Their
+  ## product is a strong Lucas pseudoprime.
+  3690125385954346893658786222051913500627130245213169388019826598097107079718295481926241398412699320815932808015860263240282855670239765686869973444864115322609857375876438922226372746215468824202413623127 1;
+  114393886964584753703422372883609318519441037601608251028614624541010319471267159939713483350793678945293917048491668160448768525777432736292969176790787575000905578652169606589017555132679533550274822316967 1;
+  158675391596036916427327807548232280526966600544166283684852543718175604427886705722828380131746070795085110744681991319332162793820309924535408858129156958872223867162686873655734028087265159440703785794503 1;
+  66981291792500223036804182765508448534715465524671325885174850970812009004775815201151227900130153990294748113034471984909912807896550069799856170439734910206802409847773026240559371480115711600866989845251707737806461503879250232804362190067578216069266197879151809743235261582813331022213587929425243163096486125825510076936556242805690400001899138503900919499414951069309064408305196756524628693684938044145785145327821174180933033293089394794328963673467918652042794300291355500468079109432376296868174257674548727592142782202898031102246775544402811199608266683925072825828225074019194302318324623049819212337927 0;
 }
 
 primeiter {
diff --git a/progs/.gitignore b/progs/.gitignore
new file mode 100644 (file)
index 0000000..b46a9e8
--- /dev/null
@@ -0,0 +1,2 @@
+/getdate.h
+/getdate.y
index 5f4e570..6de619f 100644 (file)
@@ -99,7 +99,9 @@ bin_PROGRAMS          += perftest
 ## Remember passphrases for limited periods of time.
 bin_PROGRAMS           += pixie
 pixie_SOURCES           = pixie.c
-pixie_LDADD             = $(UTILS_LIBS) $(PIXIE_LIBS) $(LOGLIBS)
+pixie_LDADD             = $(top_builddir)/base/libbase.la
+pixie_LDADD            += $(top_builddir)/key/libkey.la
+pixie_LDADD            += $(mLib_LIBS) $(PIXIE_LIBS) $(LOGLIBS)
 dist_man_MANS          += pixie.1
 EXTRA_DIST             += xpixie
 
index 6c55440..d944bfa 100644 (file)
@@ -248,9 +248,23 @@ Makes use of
 .B cipher
 and
 .B mac
-attributes.
+attributes.  Run
+.B catcrypt show cipher
+for a list of supported symmetric encryption algorithms; the default
+.I cipher
+is
+.BR blowfish-cbc .
 This is the default transform.
 .TP
+.B aead
+Use an `authenticated encryption with additional data' (AEAD) scheme.
+The specific scheme is named by the
+.B cipher
+attribute.  Run
+.B catcrypt show aead
+for a list of supported AEAD schemes; the default is
+.BR chacha20-poly1305 .
+.TP
 .B naclbox
 Use Salsa20 or ChaCha and Poly1305 to secure the bulk data.
 This is nearly the same as the NaCl
@@ -272,6 +286,11 @@ or
 .BR chacha8 ;
 the default is
 .BR salsa20 .
+Nowadays, this is equivalent to the
+.B aead
+transform, using
+.IB cipher -naclbox
+as the cipher.
 .PP
 As well as the KEM itself, a number of supporting algorithms are used.
 These are taken from appropriately named attributes on the key or,
@@ -286,11 +305,8 @@ attribute then the
 .I bulk
 in the
 .I kemalgspec
-is used; if that it absent, then the default of
-.B blowfish-cbc
-is used.  Run
-.B catcrypt show cipher
-for a list of supported symmetric encryption algorithms.
+is used; if that it absent, then the default depends on the bulk
+transform.
 .TP
 .B hash
 This is the hash function used to distil entropy from the shared secret
@@ -559,24 +575,26 @@ key-encapsulation key's
 attribute.
 .TP
 .B cipher
-The symmetric encryption algorithms which can be used in a
+The symmetric encryption algorithms which can be named in a
 key-encapsulation key's
 .B cipher
-attribute.
+attribute when using the
+.B gencomp
+bulk transform.
 .TP
 .B mac
-The message authentication algorithms which can be used in a
+The message authentication algorithms which can be named in a
 key-encapsulation key's
 .B mac
 attribute.
 .TP
 .B sig
-The signature algorithms which can be used in a signing key's
+The signature algorithms which can be named in a signing key's
 .B sig
 attribute.
 .TP
 .B hash
-The hash functions which can be used in a key's
+The hash functions which can be named in a key's
 .B hash
 attribute.
 .TP
index 72c7780..c31a3d9 100644 (file)
@@ -51,6 +51,7 @@
 #include "key.h"
 #include "cc.h"
 
+#include "gaead.h"
 #include "ectab.h"
 #include "ptab.h"
 
@@ -572,6 +573,8 @@ static int decrypt(int argc, char *argv[])
      enctab[i].name, enctab[i].name)                                   \
   LI("Symmetric encryption algorithms", cipher,                                \
      gciphertab[i], gciphertab[i]->name)                               \
+  LI("Authenticated encryption schemes", aead,                         \
+     gaeadtab[i], gaeadtab[i]->name)                                   \
   LI("Hash functions", hash,                                           \
      ghashtab[i], ghashtab[i]->name)                                   \
   LI("Message authentication codes", mac,                              \
index 1e99e05..9159ade 100644 (file)
@@ -36,6 +36,7 @@
 #include <mLib/report.h>
 #include <mLib/sub.h>
 
+#include "gaead.h"
 #include "mprand.h"
 #include "rand.h"
 
@@ -48,6 +49,7 @@
 
 #include "rmd160.h"
 #include "blowfish-cbc.h"
+#include "chacha20-poly1305.h"
 #include "poly1305.h"
 #include "salsa20.h"
 #include "chacha.h"
 
 /*----- Bulk crypto -------------------------------------------------------*/
 
-/* --- NaCl `secretbox' --- */
+/* --- Authenticated encryption schemes --- */
 
-typedef struct naclbox_encctx {
+typedef struct aead_encctx {
   bulk b;
-  const gccipher *cc;
-  gcipher *c;
-} naclbox_encctx;
+  const gcaead *aec;
+  gaead_key *key;
+  union { gaead_enc *enc; gaead_dec *dec; } ed;
+  octet *t;
+  size_t nsz, tsz;
+} aead_encctx;
 
-static bulk *naclbox_init(key *k, const char *calg, const char *halg)
+static bulk *aead_internalinit(key *k, const gcaead *aec)
 {
-  naclbox_encctx *ctx = CREATE(naclbox_encctx);
-  dstr t = DSTR_INIT;
+  aead_encctx *ctx = CREATE(aead_encctx);
+
+  ctx->key = 0;
+  ctx->aec = aec;
+  if ((ctx->nsz = keysz_pad(4, aec->noncesz)) == 0)
+    die(EXIT_FAILURE, "no suitable nonce size for `%s'", aec->name);
+  ctx->tsz = keysz(0, ctx->aec->tagsz);
+
+  return (&ctx->b);
+}
+
+static bulk *aead_init(key *k, const char *calg, const char *halg)
+{
+  const gcaead *aec;
   const char *q;
+  dstr t = DSTR_INIT;
 
   key_fulltag(k, &t);
 
   if ((q = key_getattr(0, k, "cipher")) != 0) calg = q;
-  if (!calg || strcmp(calg, "salsa20") == 0) ctx->cc = &salsa20;
-  else if (strcmp(calg, "salsa20/12") == 0) ctx->cc = &salsa2012;
-  else if (strcmp(calg, "salsa20/8") == 0) ctx->cc = &salsa208;
-  else if (strcmp(calg, "chacha20") == 0) ctx->cc = &chacha20;
-  else if (strcmp(calg, "chacha12") == 0) ctx->cc = &chacha12;
-  else if (strcmp(calg, "chacha8") == 0) ctx->cc = &chacha8;
-  else {
-    die(EXIT_FAILURE,
-       "unknown or inappropriate encryption scheme `%s' in key `%s'",
+  if (!calg) aec = &chacha20_poly1305;
+  else if ((aec = gaead_byname(calg)) == 0)
+    die(EXIT_FAILURE, "AEAD scheme `%s' not found in key `%s'",
        calg, t.buf);
-  }
 
   dstr_destroy(&t);
-  return (&ctx->b);
+  return (aead_internalinit(k, aec));
 }
 
-static int naclbox_setup(bulk *b, gcipher *cx)
+static int aead_commonsetup(aead_encctx *ctx, gcipher *cx)
 {
-  naclbox_encctx *ctx = (naclbox_encctx *)b;
-  octet k[SALSA20_KEYSZ];
+  size_t ksz, n;
 
-  GC_ENCRYPT(cx, 0, k, sizeof(k));
-  ctx->c = GC_INIT(ctx->cc, k, sizeof(k));
+  n = ksz = keysz(0, ctx->aec->keysz);
+  if (n < ctx->nsz) n = ctx->nsz;
+  if (n < ctx->tsz) n = ctx->tsz;
+  ctx->t = xmalloc(n);
+
+  GC_ENCRYPT(cx, 0, ctx->t, ksz);
+  ctx->key = GAEAD_KEY(ctx->aec, ctx->t, ksz);
   return (0);
 }
 
-static size_t naclbox_overhead(bulk *b) { return (POLY1305_TAGSZ); }
+static size_t aead_overhead(bulk *b)
+  { aead_encctx *ctx = (aead_encctx *)b; return (ctx->aec->ohd + ctx->tsz); }
 
-static void naclbox_destroy(bulk *b)
+static void aead_commondestroy(aead_encctx *ctx)
 {
-  naclbox_encctx *ctx = (naclbox_encctx *)b;
-
-  GC_DESTROY(ctx->c);
+  if (ctx->key) GAEAD_DESTROY(ctx->key);
+  xfree(ctx->t);
   DESTROY(ctx);
 }
 
-static const char *naclbox_encdoit(bulk *b, uint32 seq, buf *bb,
-                                  const void *p, size_t sz)
+static int aead_encsetup(bulk *b, gcipher *cx)
 {
-  naclbox_encctx *ctx = (naclbox_encctx *)b;
-  octet t[32];
-  poly1305_key ak;
-  poly1305_ctx a;
-  octet *tag, *ct;
+  aead_encctx *ctx = (aead_encctx *)b;
+  ctx->ed.enc = 0; return (aead_commonsetup(ctx, cx));
+}
 
-  STORE32(t, seq); STORE32(t + 4, 0); GC_SETIV(ctx->c, t);
-  GC_ENCRYPT(ctx->c, 0, t, POLY1305_KEYSZ + POLY1305_MASKSZ);
-  poly1305_keyinit(&ak, t, POLY1305_KEYSZ);
-  poly1305_macinit(&a, &ak, t + POLY1305_KEYSZ);
+static const char *aead_encdoit(bulk *b, uint32 seq, buf *bb,
+                               const void *p, size_t sz)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  octet *t;
+  int rc;
 
-  tag = buf_get(bb, POLY1305_TAGSZ); assert(tag);
-  ct = buf_get(bb, sz); assert(ct);
-  GC_ENCRYPT(ctx->c, p, ct, sz);
-  poly1305_hash(&a, ct, sz);
-  poly1305_done(&a, tag);
+  memset(ctx->t + 4, 0, ctx->nsz - 4); STORE32_B(ctx->t, seq);
+  if (!ctx->ed.enc)
+    ctx->ed.enc = GAEAD_ENC(ctx->key, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
+  else
+    GAEAD_REINIT(ctx->ed.enc, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
+  t = buf_get(bb, ctx->tsz); assert(t);
+  rc = GAEAD_ENCRYPT(ctx->ed.enc, p, sz, bb); assert(rc >= 0);
+  rc = GAEAD_DONE(ctx->ed.enc, 0, bb, t, ctx->tsz); assert(rc >= 0);
   return (0);
 }
 
-static const char *naclbox_decdoit(bulk *b, uint32 seq, buf *bb,
-                                  const void *p, size_t sz)
+static void aead_encdestroy(bulk *b)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  if (ctx->ed.enc) GAEAD_DESTROY(ctx->ed.enc);
+  aead_commondestroy(ctx);
+}
+
+static int aead_decsetup(bulk *b, gcipher *cx)
 {
-  naclbox_encctx *ctx = (naclbox_encctx *)b;
+  aead_encctx *ctx = (aead_encctx *)b;
+  ctx->ed.dec = 0; return (aead_commonsetup(ctx, cx));
+}
+
+static const char *aead_decdoit(bulk *b, uint32 seq, buf *bb,
+                               const void *p, size_t sz)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
   buf bin;
-  octet t[32];
-  poly1305_key ak;
-  poly1305_ctx a;
-  octet *tag, *ct, *pt;
+  const octet *t;
+  int rc;
 
-  STORE32(t, seq); STORE32(t + 4, 0); GC_SETIV(ctx->c, t);
-  GC_ENCRYPT(ctx->c, 0, t, POLY1305_KEYSZ + POLY1305_MASKSZ);
-  poly1305_keyinit(&ak, t, POLY1305_KEYSZ);
-  poly1305_macinit(&a, &ak, t + POLY1305_KEYSZ);
+  memset(ctx->t + 4, 0, ctx->nsz - 4); STORE32_B(ctx->t, seq);
+  if (!ctx->ed.dec)
+    ctx->ed.dec = GAEAD_DEC(ctx->key, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
+  else
+    GAEAD_REINIT(ctx->ed.enc, ctx->t, ctx->nsz, 0, sz, ctx->tsz);
 
   buf_init(&bin, (/*unconst*/ void *)p, sz);
-  if ((tag = buf_get(&bin, POLY1305_TAGSZ)) == 0) return ("no tag");
-  ct = BCUR(&bin); sz = BLEFT(&bin);
-  poly1305_hash(&a, ct, sz);
-  poly1305_done(&a, t);
-  if (!ct_memeq(t, tag, POLY1305_TAGSZ)) return ("authentication failure");
-  pt = buf_get(bb, sz); assert(pt);
-  GC_DECRYPT(ctx->c, ct, pt, sz);
+  t = buf_get(&bin, ctx->tsz); if (!t) return ("no tag");
+  rc = GAEAD_DECRYPT(ctx->ed.dec, BCUR(&bin), BLEFT(&bin), bb);
+  assert(rc >= 0);
+  rc = GAEAD_DONE(ctx->ed.dec, 0, bb, t, ctx->tsz); assert(rc >= 0);
+  if (!rc) return ("authentication failure");
   return (0);
 }
 
+static void aead_decdestroy(bulk *b)
+{
+  aead_encctx *ctx = (aead_encctx *)b;
+  if (ctx->ed.dec) GAEAD_DESTROY(ctx->ed.dec);
+  aead_commondestroy(ctx);
+}
+
+static const struct bulkops aead_encops = {
+  aead_init, aead_encsetup, aead_overhead,
+  aead_encdoit, aead_encdestroy
+}, aead_decops = {
+  aead_init, aead_decsetup, aead_overhead,
+  aead_decdoit, aead_decdestroy
+};
+
+/* --- NaCl `secretbox' in terms of AEAD --- */
+
+static bulk *naclbox_init(key *k, const char *calg, const char *halg)
+{
+  const gcaead *aec;
+  dstr t = DSTR_INIT;
+  const char *q;
+
+  key_fulltag(k, &t);
+
+  if ((q = key_getattr(0, k, "cipher")) != 0) calg = q;
+  if (!calg || strcmp(calg, "salsa20") == 0) aec = &salsa20_naclbox;
+  else if (strcmp(calg, "salsa20/12") == 0) aec = &salsa2012_naclbox;
+  else if (strcmp(calg, "salsa20/8") == 0) aec = &salsa208_naclbox;
+  else if (strcmp(calg, "chacha20") == 0) aec = &chacha20_naclbox;
+  else if (strcmp(calg, "chacha12") == 0) aec = &chacha12_naclbox;
+  else if (strcmp(calg, "chacha8") == 0) aec = &chacha8_naclbox;
+  else {
+    die(EXIT_FAILURE,
+       "unknown or inappropriate encryption scheme `%s' in key `%s'",
+       calg, t.buf);
+  }
+
+  dstr_destroy(&t);
+  return (aead_internalinit(k, aec));
+}
+
 static const bulkops naclbox_encops = {
-  naclbox_init, naclbox_setup, naclbox_overhead,
-  naclbox_encdoit, naclbox_destroy
+  naclbox_init, aead_encsetup, aead_overhead,
+  aead_encdoit, aead_encdestroy
 }, naclbox_decops = {
-  naclbox_init, naclbox_setup, naclbox_overhead,
-  naclbox_decdoit, naclbox_destroy
+  naclbox_init, aead_decsetup, aead_overhead,
+  aead_decdoit, aead_decdestroy
 };
 
 /* --- Generic composition --- */
@@ -300,6 +369,7 @@ static const bulkops gencomp_encops = {
 const struct bulktab bulktab[] = {
   { "gencomp", &gencomp_encops,        &gencomp_decops },
   { "naclbox", &naclbox_encops,        &naclbox_decops },
+  { "aead",    &aead_encops,           &aead_decops },
   { 0,         0,                      0 }
 };
 
index 8b7d3d2..6af4d51 100644 (file)
 #include <sys/time.h>
 #include <unistd.h>
 
+#ifdef HAVE_LINUX_PERF_EVENT_H
+#  include <linux/perf_event.h>
+#  include <asm/unistd.h>
+#endif
+
 #include <mLib/alloc.h>
+#include <mLib/bits.h>
 #include <mLib/dstr.h>
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
@@ -70,6 +76,7 @@
 #include "ed448.h"
 
 #include "cc.h"
+#include "gaead.h"
 #include "gcipher.h"
 #include "ghash.h"
 #include "gmac.h"
 
 typedef struct opts {
   const char *name;                    /* Pre-configured named thing */
+  const char *opwhat;                  /* What to call operations */
   unsigned fbits;                      /* Field size bits */
   unsigned gbits;                      /* Group size bits */
   unsigned n;                          /* Number of factors */
   unsigned i;                          /* Number of intervals (or zero) */
+  unsigned k;                          /* Main loop batch size */
+  unsigned long sc;                    /* Scale factor */
   double t;                            /* Time for each interval (secs) */
   mp *e;                               /* Public exponent */
   unsigned f;                          /* Flags */
@@ -495,7 +505,9 @@ static void *ksched_init(opts *o)
     die(1, "must specify encryption scheme name");
   if ((c->c = gcipher_byname(o->name)) == 0)
     die(1, "encryption scheme `%s' not known", o->name);
-  c->ksz = keysz(o->gbits/8, c->c->keysz);
+  c->ksz = keysz(o->fbits/8, c->c->keysz);
+  if (o->fbits%8 || (o->fbits && c->ksz != o->fbits/8))
+    die(1, "bad key size %u for %s", o->fbits, o->name);
   c->k = xmalloc(c->ksz);
   rand_get(RAND_GLOBAL, c->k, c->ksz);
   return (c);
@@ -525,13 +537,16 @@ static void *enc_init(opts *o)
     die(1, "must specify encryption scheme name");
   if ((cc = gcipher_byname(o->name)) == 0)
     die(1, "encryption scheme `%s' not known", o->name);
-  ksz = keysz(0, cc->keysz);
+  ksz = keysz(o->fbits/8, cc->keysz);
+  if (o->fbits%8 || (o->fbits && ksz != o->fbits/8))
+    die(1, "bad key size %u for %s", o->fbits, o->name);
   k = xmalloc(ksz);
   rand_get(RAND_GLOBAL, k, ksz);
   c->c = GC_INIT(cc, k, ksz);
   xfree(k);
   c->sz = o->gbits ? o->gbits : 65536;
   c->n = o->n ? o->n : 16;
+  o->opwhat = "byte"; o->sc = c->n*c->sz;
   c->m = xmalloc(c->sz);
   return (c);
 }
@@ -544,6 +559,105 @@ static void enc_run(void *cc)
     GC_ENCRYPT(c->c, c->m, c->m, c->sz);
 }
 
+/* --- Authenticated encryption --- */
+
+typedef struct aeadsetup_ctx {
+  const gcaead *aec;
+  octet *k; size_t ksz;
+  octet *n; size_t nsz;
+  size_t tsz;
+} aeadsetup_ctx;
+
+static void *aeadsetup_init(opts *o)
+{
+  aeadsetup_ctx *c = CREATE(aeadsetup_ctx);
+  if (!o->name)
+    die(1, "must specify encryption scheme name");
+  if ((c->aec = gaead_byname(o->name)) == 0)
+    die(1, "aead scheme `%s' not known", o->name);
+  c->ksz = keysz(o->fbits/8, c->aec->keysz);
+  c->nsz = keysz_pad(o->gbits/8, c->aec->noncesz);
+  c->tsz = keysz(0, c->aec->tagsz);
+  if (o->fbits%8 || (o->fbits && c->ksz != o->fbits/8))
+    die(1, "bad key size %u for %s", o->fbits, o->name);
+  if (o->gbits%8 || (o->gbits && c->nsz != o->gbits/8))
+    die(1, "bad nonce size %u for %s", o->gbits, o->name);
+  c->k = xmalloc(c->ksz); rand_get(RAND_GLOBAL, c->k, c->ksz);
+  c->n = xmalloc(c->nsz); rand_get(RAND_GLOBAL, c->n, c->nsz);
+  return (c);
+}
+
+static void aeadsetup_run(void *cc)
+{
+  aeadsetup_ctx *c = cc;
+  gaead_key *k = GAEAD_KEY(c->aec, c->k, c->ksz);
+  gaead_enc *e = GAEAD_ENC(k, c->n, c->nsz, 0, 0, c->tsz);
+  GAEAD_DESTROY(e); GAEAD_DESTROY(k);
+}
+
+typedef struct aeadenc_ctx {
+  gaead_enc *enc;
+  octet *n; size_t nsz;
+  octet *p, *q; size_t sz; size_t nn;
+  size_t tsz;
+} aeadenc_ctx;
+
+static void *aeadenc_init(opts *o)
+{
+  aeadenc_ctx *c = CREATE(aeadenc_ctx);
+  const gcaead *aec;
+  gaead_key *key;
+  octet *k; size_t ksz;
+
+  if (!o->name)
+    die(1, "must specify encryption scheme name");
+  if ((aec = gaead_byname(o->name)) == 0)
+    die(1, "aead scheme `%s' not known", o->name);
+  c->sz = o->gbits ? o->gbits : 65536;
+  c->nn = o->n ? o->n : 16;
+  ksz = keysz(o->fbits/8, aec->keysz);
+  c->nsz = keysz(0, aec->noncesz);
+  c->tsz = keysz(0, aec->tagsz);
+  if (o->fbits%8 || (o->fbits && ksz != o->fbits/8))
+    die(1, "bad key size %u for %s", o->fbits, o->name);
+
+  k = xmalloc(ksz); rand_get(RAND_GLOBAL, k, ksz);
+  c->n = xmalloc(c->nsz); rand_get(RAND_GLOBAL, c->n, c->nsz);
+  c->p = xmalloc(c->sz); c->q = xmalloc(c->sz + aec->bufsz);
+
+  key = GAEAD_KEY(aec, k, ksz);
+  c->enc = GAEAD_ENC(key, c->n, c->nsz, 0, 0, c->tsz);
+  GAEAD_DESTROY(key); xfree(k);
+
+  o->opwhat = "byte"; o->sc = c->nn*c->sz;
+  return (c);
+}
+
+static void aeadaad_run(void *cc)
+{
+  aeadenc_ctx *c = cc;
+  gaead_aad *a;
+  size_t i;
+
+  GAEAD_REINIT(c->enc, c->n, c->nsz, c->nn*c->sz, 0, c->tsz);
+  a = GAEAD_AAD(c->enc);
+  for (i = 0; i < c->nn; i++) GAEAD_HASH(a, c->p, c->sz);
+  GAEAD_DESTROY(a);
+}
+
+static void aeadenc_run(void *cc)
+{
+  aeadenc_ctx *c = cc;
+  buf b;
+  size_t i;
+
+  GAEAD_REINIT(c->enc, c->n, c->nsz, 0, c->nn*c->sz, c->tsz);
+  for (i = 0; i < c->nn; i++) {
+    buf_init(&b, c->q, c->sz + c->enc->ops->c->bufsz);
+    GAEAD_ENCRYPT(c->enc, c->p, c->sz, &b);
+  }
+}
+
 /* --- Hashing --- */
 
 typedef struct hash_ctx {
@@ -562,6 +676,7 @@ static void *hash_init(opts *o)
     die(1, "hash function `%s' not known", o->name);
   c->sz = o->gbits ? o->gbits : 65536;
   c->n = o->n ? o->n : 16;
+  o->opwhat = "byte"; o->sc = c->n*c->sz;
   c->m = xmalloc(c->sz);
   return (c);
 }
@@ -596,6 +711,7 @@ static void *poly1305_jobinit(opts *o)
   rand_get(RAND_GLOBAL, c->s, sizeof(c->s));
   c->sz = o->gbits ? o->gbits : 65536;
   c->n = o->n ? o->n : 16;
+  o->opwhat = "byte"; o->sc = c->n*c->sz;
   c->m = xmalloc(c->sz);
   return (c);
 }
@@ -639,11 +755,81 @@ static const jobops jobtab[] = {
   { "ed448-vrf",               ed448_vrfinit,          ed448_vrfrun },
   { "ksched",                  ksched_init,            ksched_run },
   { "enc",                     enc_init,               enc_run },
+  { "aead-setup",              aeadsetup_init,         aeadsetup_run },
+  { "aead-aad",                        aeadenc_init,           aeadaad_run },
+  { "aead-enc",                        aeadenc_init,           aeadenc_run },
   { "hash",                    hash_init,              hash_run },
   { "poly1305",                        poly1305_jobinit,       poly1305_jobrun },
   { 0,                         0,                      0 }
 };
 
+/*----- Cycle counting ----------------------------------------------------*/
+
+typedef kludge64 cycles;
+static int cyclecount_active_p = 0;
+
+#if defined(__GNUC__) && (CPUFAM_X86 || CPUFAM_AMD64)
+
+static void init_cyclecount(void) { cyclecount_active_p = 1; }
+
+static cycles cyclecount(void)
+{
+  uint32 lo, hi;
+  kludge64 cy;
+
+  __asm__("rdtsc" : "=a"(lo), "=d"(hi));
+  SET64(cy, hi, lo);
+  return cy;
+}
+
+#elif defined(HAVE_LINUX_PERF_EVENT_H) && defined(HAVE_UINT64)
+
+static int perf_fd = -1;
+
+static void init_cyclecount(void)
+{
+  struct perf_event_attr attr = { 0 };
+
+  attr.type = PERF_TYPE_HARDWARE;
+  attr.size = sizeof(attr);
+  attr.config = PERF_COUNT_HW_CPU_CYCLES;
+  attr.disabled = 0;
+  attr.exclude_kernel = 1;
+  attr.exclude_hv = 1;
+
+  if ((perf_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0)) < 0)
+    moan("failed to open perf event: %s", strerror(errno));
+  else
+    cyclecount_active_p = 1;
+}
+
+static cycles cyclecount(void)
+{
+  kludge64 cy;
+  ssize_t n;
+
+  if (!cyclecount_active_p)
+    goto fail;
+  else if ((n = read(perf_fd, &cy.i, sizeof(cy.i))) != sizeof(cy.i)) {
+    if (n < 0) moan("error reading perf event: %s", strerror(errno));
+    else moan("unexpected short read from perf event");
+    cyclecount_active_p = 0; close(perf_fd); perf_fd = -1;
+    goto fail;
+  }
+end:
+  return (cy);
+fail:
+  SET64(cy, 0, 0);
+  goto end;
+}
+
+#else
+
+static void init_cyclecount(void) { cyclecount_active_p = 0; }
+static cycles cyclecount(void) { kludge64 cy; SET64(cy, 0, 0); return (cy); }
+
+#endif
+
 /*----- Main code ---------------------------------------------------------*/
 
 void version(FILE *fp)
@@ -672,13 +858,15 @@ Options:\n\
 -l, --list [ITEM...]   List all the various names of things.\n\
 \n\
 -C, --name=NAME                Select curve/DH-group/enc/hash name.\n\
--b, --field-bits       Field size for g-prime and rsa.\n\
+-b, --field-bits       Field size for g-prime and rsa;\n\
+                         key bits for ksched, enc, aead-setup, aead-enc.\n\
 -q, --no-check         Don't check field/group for validity.\n\
--B, --group-bits       Group size for g-prime; key size for ksched;\n\
-                         data size for enc and hash.\n\
+-B, --group-bits       Group size for g-prime; nonce bits for aead-setup;\n\
+                         data size for enc, aead-aad, aead-enc, and hash.\n\
 -n, --factors=COUNT    Number of factors for {exp,mul}-sim;\n\
-                         inner iterations for enc and hash.\n\
+                         inner iters for enc, aead-aad, aead-enc, hash.\n\
 -i, --intervals=COUNT  Number of intervals to run for.  [0; forever]\n\
+-k, --batch=COUNT      Number of operations to batch between timer checks.\n\
 -t, --time=TIME                Length of an interval in seconds.  [1]\n\
 ");
 }
@@ -694,6 +882,8 @@ Options:\n\
      ptab[i].name, ptab[i].name)                                       \
   LI("Encryption algorithms", cipher,                                  \
      gciphertab[i], gciphertab[i]->name)                               \
+  LI("Authenticated encryption schemes", aead,                         \
+     gaeadtab[i], gaeadtab[i]->name)                                   \
   LI("Hash functions", hash,                                           \
      ghashtab[i], ghashtab[i]->name)
 
@@ -735,15 +925,16 @@ int main(int argc, char *argv[])
   opts o = { 0 };
   const jobops *j;
   struct timeval tv_next, tv_now;
-  double t, ttot;
-  unsigned n;
+  double t, ttot, cy, cytot;
+  unsigned n, k;
   unsigned long ii;
-  clock_t c_start, c_stop;
+  clock_t c0, c1;
+  kludge64 cy0, cy1, cydiff;
   double itot;
   void *p;
 
   ego(argv[0]);
-  o.t = 1;
+  o.t = 1; o.k = 1; o.sc = 1; o.opwhat = "op";
   for (;;) {
     static const struct option opts[] = {
       { "help",                0,              0,      'h' },
@@ -755,13 +946,14 @@ int main(int argc, char *argv[])
       { "group-bits",  OPTF_ARGREQ,    0,      'B' },
       { "factors",     OPTF_ARGREQ,    0,      'n' },
       { "intervals",   OPTF_ARGREQ,    0,      'i' },
+      { "batch",       OPTF_ARGREQ,    0,      'k' },
       { "public-exponent", OPTF_ARGREQ, 0,     'e' },
       { "time",                OPTF_ARGREQ,    0,      't' },
       { "no-check",    0,              0,      'q' },
       { 0,             0,              0,      0 }
     };
 
-    i = mdwopt(argc, argv, "hvulC:b:B:n:i:e:t:q", opts, 0, 0, 0);
+    i = mdwopt(argc, argv, "hvulC:b:B:n:i:k:e:t:q", opts, 0, 0, 0);
     if (i < 0) break;
     switch (i) {
       case 'h': help(stdout); exit(0);
@@ -779,6 +971,7 @@ int main(int argc, char *argv[])
        break;
       case 'i': o.i = uarg("interval count", optarg); break;
       case 't': o.t = farg("interval length", optarg); break;
+      case 'k': o.k = uarg("batch size", optarg); break;
       case 'q': o.f |= OF_NOCHECK; break;
       default: usage(stderr); exit(1);
     }
@@ -791,23 +984,29 @@ int main(int argc, char *argv[])
   p = j->init(&o);
 
   n = 0;
-  ttot = itot =         0;
+  ttot = itot = 0; cytot = 0; init_cyclecount();
   gettimeofday(&tv_now, 0);
   do {
     tv_addl(&tv_next, &tv_now, o.t, fmod(o.t * MILLION, MILLION));
     ii = 0;
-    c_start = clock();
+    c0 = clock(); cy0 = cyclecount();
     do {
-      j->run(p);
-      ii++;
+      for (k = 0; k < o.k; k++) { j->run(p); }
+      ii += k;
       gettimeofday(&tv_now, 0);
     } while (TV_CMP(&tv_now, <, &tv_next));
-    c_stop = clock();
-    t = (double)(c_stop - c_start)/CLOCKS_PER_SEC;
-    itot += ii;
-    ttot += t;
-    printf("%5u: did = %5lu; /sec = %5f; avg /sec = %5f\n",
+    cy1 = cyclecount(); c1 = clock();
+    t = (double)(c1 - c0)/CLOCKS_PER_SEC;
+    itot += ii; ttot += t;
+    printf("%5u: did = %5lu; /sec = %5f; avg /sec = %5f",
           n, ii, ii/t, itot/ttot);
+    if (cyclecount_active_p) {
+      SUB64(cydiff, cy1, cy0); cy = LO64(cydiff) + ldexp(HI64(cydiff), 32);
+      cytot += cy;
+      printf(" (cy/%s = %3f; avg cy/%s = %3f)",
+            o.opwhat, cy/ii/o.sc, o.opwhat, cytot/itot/o.sc);
+    }
+    putchar('\n');
     fflush(stdout);
     n++;
   } while (!o.i || n < o.i);
index b593fb8..69e2437 100644 (file)
@@ -126,7 +126,7 @@ int main(int argc, char *argv[])
     group *g;
     dh_infofromdata(&dp, pe->data);
     g = group_prime(&dp);
-    if (mp_bits(dp.p) > 2048 &&
+    if (mp_bits(dp.p) > 3072 &&
        (!argv[1] || strcmp(argv[1], "keen") != 0)) {
       printf(" [%s skipped]", pe->name);
       fflush(stdout);
index 55e2c17..5c18b12 100644 (file)
@@ -1 +1,69 @@
-modes/
+/modes/
+/modes.am
+/stubs.am
+/stubs.gen-stamp
+
+/t/salsa20
+/t/sha3
+
+/sha224.c
+/sha224.h
+/sha384.h
+/sha384.c
+/sha512-224.c
+/sha512-224.h
+/sha512-256.c
+/sha512-256.h
+
+/safersk.c
+/safersk.h
+
+/whirlpool256.c
+/whirlpool256.h
+
+/sha3-224.c
+/sha3-224.h
+/sha3-256.c
+/sha3-256.h
+/sha3-384.c
+/sha3-384.h
+/sha3-512.c
+/sha3-512.h
+/kmac128.h
+/kmac256.h
+/shake128.h
+/shake256.h
+/shake128-xof.h
+/shake256-xof.h
+
+/chacha20.h
+/chacha12.h
+/chacha8.h
+/chacha12-ietf.h
+/chacha20-ietf.h
+/chacha8-ietf.h
+/xchacha.h
+/xchacha20.h
+/xchacha12.h
+/xchacha8.h
+/chacha20-naclbox.h
+/chacha12-naclbox.h
+/chacha8-naclbox.h
+/chacha20-poly1305.h
+/chacha12-poly1305.h
+/chacha8-poly1305.h
+
+/salsa2012.h
+/salsa208.h
+/salsa20-ietf.h
+/salsa2012-ietf.h
+/salsa208-ietf.h
+/xsalsa20.h
+/xsalsa2012.h
+/xsalsa208.h
+/salsa20-naclbox.h
+/salsa2012-naclbox.h
+/salsa208-naclbox.h
+/salsa20-poly1305.h
+/salsa2012-poly1305.h
+/salsa208-poly1305.h
index 6a0683c..68d9267 100644 (file)
@@ -32,6 +32,11 @@ nodist_libsymm_la_SOURCES =
 
 TEST_LIBS               = libsymm.la
 
+noinst_LTLIBRARIES     += libsymmtest.la
+libsymmtest_la_SOURCES  =
+libsymmtest_la_CFLAGS   = $(AM_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+TEST_LIBS              += libsymmtest.la
+
 VPATH                  += $(srcdir)/modes
 
 ###--------------------------------------------------------------------------
@@ -63,6 +68,8 @@ $(srcdir)/modes.am: modes.am.in Makefile.am
                blkc="$(BLKCS)" \
                        blkcmode="$(BLKCMODES)" \
                        blkcciphermode="$(BLKCCIPHERMODES)" \
+                       blkcaeadmode="$(BLKCAEADMODES)" \
+                       blkcmacmode="$(BLKCMACMODES)" \
                hash="$(HASHES)" \
                        hashmode="$(HASHMODES)" \
                        hashciphermode="$(HASHCIPHERMODES)" \
@@ -73,6 +80,7 @@ $(srcdir)/stubs.am: stubs.am.in Makefile.am
 
 ## Initialize lists of known classes.
 ALL_CIPHERS             = $(CIPHER_MODES)
+ALL_AEADS               = $(AEAD_MODES)
 ALL_HASHES              = $(HASHES)
 ALL_MACS                = $(MAC_MODES)
 
@@ -89,6 +97,12 @@ BLKCMODES             =
 BLKCCIPHERMODES                 =
 BLKCMODES              += $(BLKCCIPHERMODES)
 
+BLKCAEADMODES           =
+BLKCMODES              += $(BLKCAEADMODES)
+
+BLKCMACMODES            =
+BLKCMODES              += $(BLKCMACMODES)
+
 ## A tool for translating the AES-contest test vectors into a form our test
 ## rigs understand.
 EXTRA_DIST             += aes-trans
@@ -119,13 +133,14 @@ endif
 BLKCS                  += cast128 cast256
 libsymm_la_SOURCES     += cast-s.c cast-sk.c cast-base.h
 cast256.log: t/cast256
-EXTRA_DIST             += t/cast256.aes
+EXTRA_DIST             += t/cast256.aes t/cast256.local
 MAINTAINERCLEANFILES   += $(srcdir)/t/cast256
-t/cast256: t/cast256.aes
-       $(AM_V_GEN)$(srcdir)/aes-trans CAST256 \
-               <$(srcdir)/t/cast256.aes \
-               >$(srcdir)/t/cast256.new && \
-       mv $(srcdir)/t/cast256.new $(srcdir)/t/cast256
+t/cast256: t/cast256.aes t/cast256.local
+       $(AM_V_GEN)cd $(srcdir) && \
+               { ./aes-trans CAST256 <t/cast256.aes && \
+                 cat t/cast256.local; \
+               } >t/cast256.new && \
+               mv t/cast256.new t/cast256
 
 ## IBM's `DES' block cipher, by Feistel, Coppersmith, and others.
 BLKCS                  += des des3
@@ -161,13 +176,14 @@ $(precomp)/symm/mars-tab.c:
                mv $(precomp)/symm/mars-tab.c.new $(precomp)/symm/mars-tab.c
 endif
 mars.log: t/mars
-EXTRA_DIST             += t/mars.aes
+EXTRA_DIST             += t/mars.aes t/mars.local
 MAINTAINERCLEANFILES   += $(srcdir)/t/mars
-t/mars: t/mars.aes
-       $(AM_V_GEN)$(srcdir)/aes-trans Mars \
-               <$(srcdir)/t/mars.aes \
-               >$(srcdir)/t/mars.new && \
-       mv $(srcdir)/t/mars.new $(srcdir)/t/mars
+t/mars: t/mars.aes t/mars.local
+       $(AM_V_GEN)cd $(srcdir) && \
+               { ./aes-trans Mars <t/mars.aes && \
+                 cat t/mars.local; \
+               } >t/mars.new && \
+               mv t/mars.new t/mars
 
 ## Daemen, Peeters, Van Assche and Rijmen's `Noekeon'.
 BLKCS                  += noekeon
@@ -208,13 +224,14 @@ $(precomp)/symm/rijndael-tab.c:
                        $(precomp)/symm/rijndael-tab.c
 endif
 rijndael.log: t/rijndael
-EXTRA_DIST             += t/rijndael.aes
+EXTRA_DIST             += t/rijndael.aes t/rijndael.local
 MAINTAINERCLEANFILES   += $(srcdir)/t/rijndael
-t/rijndael: t/rijndael.aes
-       $(AM_V_GEN)$(srcdir)/aes-trans Rijndael \
-               <$(srcdir)/t/rijndael.aes \
-               >$(srcdir)/t/rijndael.new && \
-       mv $(srcdir)/t/rijndael.new $(srcdir)/t/rijndael
+t/rijndael: t/rijndael.aes t/rijndael.local
+       $(AM_V_GEN)cd $(srcdir) && \
+               { ./aes-trans Rijndael <t/rijndael.aes && \
+                 cat t/rijndael.local; \
+               } >t/rijndael.new && \
+               mv t/rijndael.new t/rijndael
 
 ## Massey's `SAFER' block ciphers.
 BLKCS                  += safer safersk
@@ -238,13 +255,14 @@ libsymm_la_SOURCES        += serpent-sbox.h
 check_PROGRAMS         += serpent-check
 TESTS                  += serpent-check
 serpent.log: t/serpent
-EXTRA_DIST             += t/serpent.aes
+EXTRA_DIST             += t/serpent.aes t/serpent.local
 MAINTAINERCLEANFILES   += $(srcdir)/t/serpent
-t/serpent: t/serpent.aes
-       $(AM_V_GEN)$(srcdir)/aes-trans Serpent -v rev=1 \
-               <$(srcdir)/t/serpent.aes \
-               >$(srcdir)/t/serpent.new && \
-       mv $(srcdir)/t/serpent.new $(srcdir)/t/serpent
+t/serpent: t/serpent.aes t/serpent.local
+       $(AM_V_GEN)cd $(srcdir) && \
+               { ./aes-trans Serpent -v rev=1 <t/serpent.aes && \
+                 cat t/serpent.local; \
+               } >t/serpent.new && \
+               mv t/serpent.new t/serpent
 
 ## The National Security Agency's `Skipjack' block cipher.  You don't want to
 ## use this.
@@ -283,13 +301,14 @@ $(precomp)/symm/twofish-tab.c:
                        $(precomp)/symm/twofish-tab.c
 endif
 twofish.log: t/twofish
-EXTRA_DIST             += t/twofish.aes
+EXTRA_DIST             += t/twofish.aes t/twofish.local
 MAINTAINERCLEANFILES   += $(srcdir)/t/twofish
-t/twofish: t/twofish.aes
-       $(AM_V_GEN)$(srcdir)/aes-trans Twofish \
-               <$(srcdir)/t/twofish.aes \
-               >$(srcdir)/t/twofish.new && \
-       mv $(srcdir)/t/twofish.new $(srcdir)/t/twofish
+t/twofish: t/twofish.aes t/twofish.local
+       $(AM_V_GEN)cd $(srcdir) && \
+               { ./aes-trans Twofish <t/twofish.aes && \
+                 cat t/twofish.local; \
+               } >t/twofish.new && \
+               mv t/twofish.new t/twofish
 
 ## The old NIST modes for DES.
 BLKCCIPHERMODES                += cbc cfb ecb ofb
@@ -297,6 +316,29 @@ BLKCCIPHERMODES            += cbc cfb ecb ofb
 ## Counter mode.
 BLKCCIPHERMODES                += counter
 
+## CMAC mode.
+BLKCMACMODES           += cmac pmac1
+
+## Various AEAD modes.
+pkginclude_HEADERS     += ocb.h
+BLKCAEADMODES          += ccm eax gcm ocb1 ocb3
+libsymm_la_SOURCES     += ccm.c gcm.c ocb.c
+if CPUFAM_X86
+libsymm_la_SOURCES     += gcm-x86ish-pclmul.S
+endif
+if CPUFAM_AMD64
+libsymm_la_SOURCES     += gcm-x86ish-pclmul.S
+endif
+if CPUFAM_ARMEL
+libsymm_la_SOURCES     += gcm-arm-crypto.S
+endif
+if CPUFAM_ARM64
+libsymm_la_SOURCES     += gcm-arm64-pmull.S
+endif
+
+TESTS                  += gcm.t$(EXEEXT)
+EXTRA_DIST             += t/gcm
+
 ###--------------------------------------------------------------------------
 ### Hash functions.
 
@@ -555,6 +597,32 @@ poly1305_p11_t_LDFLAGS      = $(TEST_LDFLAGS)
 poly1305_p11_t_LDADD    = $(TEST_LIBS) $(top_builddir)/libcatacomb.la
 poly1305_p11_t_LDADD   += $(mLib_LIBS) $(CATACOMB_LIBS) $(LIBS)
 
+## Combining Salsa20/ChaCha with Poly1305.
+pkginclude_HEADERS     += latinpoly.h latinpoly-def.h
+libsymm_la_SOURCES     += latinpoly.c chacha-poly1305.c salsa20-poly1305.c
+libsymmtest_la_SOURCES += latinpoly-test.c latinpoly-test.h
+
+ALL_AEADS              += chacha20-poly1305 salsa20-poly1305
+ALL_AEADS              += chacha12-poly1305 salsa2012-poly1305
+ALL_AEADS              += chacha8-poly1305 salsa208-poly1305
+ALL_AEADS              += chacha20-naclbox salsa20-naclbox
+ALL_AEADS              += chacha12-naclbox salsa2012-naclbox
+ALL_AEADS              += chacha8-naclbox salsa208-naclbox
+STUBS_HDR              += ChaCha20-Poly1305,chacha20-poly1305,latinpoly
+STUBS_HDR              += ChaCha12-Poly1305,chacha12-poly1305,latinpoly
+STUBS_HDR              += ChaCha8-Poly1305,chacha8-poly1305,latinpoly
+STUBS_HDR              += Salsa20-Poly1305,salsa20-poly1305,latinpoly
+STUBS_HDR              += Salsa20/12-Poly1305,salsa2012-poly1305,latinpoly
+STUBS_HDR              += Salsa20/8-Poly1305,salsa208-poly1305,latinpoly
+STUBS_HDR              += ChaCha20-NaClBox,chacha20-naclbox,latinpoly
+STUBS_HDR              += ChaCha12-NaClBox,chacha12-naclbox,latinpoly
+STUBS_HDR              += ChaCha8-NaClBox,chacha8-naclbox,latinpoly
+STUBS_HDR              += Salsa20-NaClBox,salsa20-naclbox,latinpoly
+STUBS_HDR              += Salsa20/12-NaClBox,salsa2012-naclbox,latinpoly
+STUBS_HDR              += Salsa20/8-NaClBox,salsa208-naclbox,latinpoly
+TESTS                  += chacha-poly1305.t$(EXEEXT)
+TESTS                  += salsa20-poly1305.t$(EXEEXT)
+
 ###--------------------------------------------------------------------------
 ### Autogenerated mode implementations.
 
@@ -593,6 +661,9 @@ MAINTAINERCLEANFILES        += $(GENMODES_H)
 pkginclude_HEADERS     += $(GENMODES_H)
 $(GENMODES_H): modes/gen-stamp
 
+## Additional test machinery.
+libsymmtest_la_SOURCES += modes-test.c modes-test.h
+
 ###--------------------------------------------------------------------------
 ### Autogenerated stub headers.
 
@@ -628,6 +699,15 @@ gciphertab.c: gthingtab.c.in Makefile.am
        $(AM_V_GEN)$(multigen) -g $(srcdir)/gthingtab.c.in gciphertab.c \
                what=gcipher cls=gccipher thing="$(ALL_CIPHERS)"
 
+## Table of AEAD classes.
+pkginclude_HEADERS     += gaead.h
+CLEANFILES             += gaeadtab.c
+libsymm_la_SOURCES     += gaead.c
+nodist_libsymm_la_SOURCES += gaeadtab.c
+gaeadtab.c: gthingtab.c.in Makefile.am
+       $(AM_V_GEN)$(multigen) -g $(srcdir)/gthingtab.c.in gaeadtab.c \
+               what=gaead cls=gcaead thing="$(ALL_AEADS)"
+
 ## Table of hash classes.
 pkginclude_HEADERS     += ghash.h ghash-def.h
 CLEANFILES             += ghashtab.c
@@ -650,9 +730,13 @@ gmactab.c: gthingtab.c.in Makefile.am
 ## Run the test programs.
 TESTS                  += $(SYMM_TESTS)
 EXTRA_DIST             += $(SYMM_TEST_FILES)
+EXTRA_DIST             += $(REGRESSION_TEST_FILES)
 
-## A piece of sample text for round-trip testing encryption modes.
-EXTRA_DIST             += daftstory.h
+t/modes/%.regress:
+       $(MAKE) modes/$*.t && \
+               mkdir -p $(srcdir)/t/modes/ && \
+               modes/$*.t -o$(srcdir)/$@.new && \
+               mv $(srcdir)/$@.new $(srcdir)/$@
 
 ## Clean the debris from the `modes' subdirectory.
 CLEANFILES             += modes/*.to modes/*.t$(EXEEXT)
index ff631f0..bbba763 100644 (file)
@@ -69,6 +69,8 @@
 #define BLKC_STORE_E(PRE) BLKC_GLUE(STORE32_, BLKC_ENDIAN(PRE))
 #define BLKC_LOAD_E(PRE) BLKC_GLUE(LOAD32_, BLKC_ENDIAN(PRE))
 
+#define BLKC_ID(x) (x)
+
 /* --- Interface macros --- */
 
 #define BLKC_STORE(PRE, b, w)                                          \
   BLKC_GLUE(BLKC_XMOVE_, BLKC_TYPE(PRE))                               \
     (PRE, w, wx, BLKC_BITS(PRE))
 
-#define BLKC_STEP(PRE, w)                                              \
-  BLKC_GLUE(BLKC_STEP_X_, BLKC_ENDIAN(PRE))                            \
-    (PRE, w)
+#define BLKC_BSTEP(PRE, w) BLKC_BADD(PRE, w, 1)
+#define BLKC_LSTEP(PRE, w) BLKC_LADD(PRE, w, 1)
+#define BLKC_STEP(PRE, w) BLKC_ADD(PRE, w, 1)
+
+#define BLKC_BADD(PRE, w, n)                                           \
+  BLKC_GLUE(BLKC_BADD_X_, BLKC_ENDIAN(PRE))                            \
+    (PRE, w, n)
+#define BLKC_LADD(PRE, w, n)                                           \
+  BLKC_GLUE(BLKC_LADD_X_, BLKC_ENDIAN(PRE))                            \
+    (PRE, w, n)
+#define BLKC_ADD(PRE, w, n)                                            \
+  BLKC_GLUE(BLKC_ADD_X_, BLKC_ENDIAN(PRE))                             \
+    (PRE, BLKC_ID, w, n)
 
 #define BLKC_ZERO(PRE, w)                                              \
   BLKC_GLUE(BLKC_ZERO_, BLKC_TYPE(PRE))                                        \
     (PRE, w, BLKC_BITS(PRE))
 
+#define BLKC_BSET(PRE, w, x)                                           \
+  BLKC_GLUE(BLKC_BSET_X_, BLKC_ENDIAN(PRE))                            \
+    (PRE, w, x)
+#define BLKC_LSET(PRE, w, x)                                           \
+  BLKC_GLUE(BLKC_LSET_X_, BLKC_ENDIAN(PRE))                            \
+    (PRE, w, x)
 #define BLKC_SET(PRE, w, x)                                            \
   BLKC_GLUE(BLKC_SET_X_, BLKC_ENDIAN(PRE))                             \
-    (PRE, w, x)
+    (PRE, BLKC_ID, w, x)
+
+#define BLKC_BWORD(PRE, x) BLKC_GLUE(BLKC_BWORD_, BLKC_ENDIAN(PRE))(x)
+#define BLKC_LWORD(PRE, x) BLKC_GLUE(BLKC_LWORD_, BLKC_ENDIAN(PRE))(x)
 
 #define BLKC_SHOW(PRE, tag, w) do {                                    \
   fputs(tag ": ", stdout);                                             \
-  BLKC_SKEL_X(PRE, BLKC_W(w);, printf("%08x ", *_w++););               \
+  BLKC_SKEL_X(PRE, const BLKC_W(w);,                                   \
+             { printf("%08x ", BLKC_BWORD(PRE, *_w)); _w++; });        \
   fputc('\n', stdout);                                                 \
 } while (0)
 
+/* --- Utilities --- *
+ *
+ * These seem too hard to properly generalize, or I'd have put them in
+ * <mLib/bits.h>.
+ */
+
+#ifdef HAVE_UINT64
+#  define BLKC_ADDC32(op, z_out, c_out, x, y) do {                     \
+     uint64 _t = (uint64)op(x) + (y);                                  \
+     (z_out) = U32(op(_t)); (c_out) = _t >> 32;                                \
+   } while (0)
+#else
+#  define BLKC_ADDC32(op, z_out, c_out, x, y) do {                     \
+     uint32 _x = op(x), _c = 0, _t;                                    \
+     _t = U32(_x + (y)); (z_out) = op(_t); (c_out) = (_t < _x);                \
+   } while (0)
+#endif
+
 /* --- General implementation skeleton --- */
 
 #define BLKC_SKEL(PRE, decl, guts) do {                                        \
   guts                                                                 \
 } while (0)
 
-#define BLKC_P(p) register octet *_p = (octet *)(p)
-#define BLKC_W(w) register uint32 *_w = (w)
-#define BLKC_WX(wx) register uint32 *_wx = (wx)
+#define BLKC_P(p) octet *_p = (octet *)(p)
+#define BLKC_W(w) uint32 *_w = (w)
+#define BLKC_WX(wx) uint32 *_wx = (wx)
 
 /* --- Implementation for unusual block sizes --- */
 
 #define BLKC_SKEL_X(PRE, decl, guts)                                   \
   BLKC_SKEL(PRE, unsigned _i; decl,                                    \
-           for (_i = 0; _i < PRE##_BLKSZ / 4; _i++) {                  \
+           for (_i = 0; _i < PRE##_BLKSZ/4; _i++) {                    \
              guts                                                      \
            })
 
 #define BLKC_ZERO_X(PRE, w, n)                                         \
   BLKC_SKEL_X(PRE, BLKC_W(w);, *_w++ = 0;)
 
-#define BLKC_STEP_X_B(PRE, w) do {                                     \
-  unsigned _i = PRE##_BLKSZ / 4; BLKC_W(w); uint32 _x = 0;             \
-  while (_i && !_x) { _i--; _w[_i] = _x = U32(_w[_i] + 1); }           \
+#define BLKC_BADD_X_B(PRE, w, n) BLKC_ADD_X_B(PRE, BLKC_ID, w, n)
+#define BLKC_BADD_X_L(PRE, w, n) BLKC_ADD_X_B(PRE, ENDSWAP32, w, n)
+#define BLKC_LADD_X_B(PRE, w, n) BLKC_ADD_X_L(PRE, ENDSWAP32, w, n)
+#define BLKC_LADD_X_L(PRE, w, n) BLKC_ADD_X_L(PRE, BLKC_ID, w, n)
+
+#define BLKC_ADD_X_B(PRE, op, w, n) do {                               \
+  unsigned _i = PRE##_BLKSZ/4; BLKC_W(w); uint32 _n = (n);             \
+  while (_i-- && _n) BLKC_ADDC32(op, _w[_i], _n, _w[_i], _n);          \
 } while (0)
 
-#define BLKC_STEP_X_L(PRE, w) do {                                     \
-  unsigned _i = 0; BLKC_W(w); uint32 _x = 0;                           \
-  while (_i < PRE##_BLKSZ / 4 && !_x)                                  \
-    { _w[_i] = _x = U32(_w[_i] + 1); _i++; }                           \
+#define BLKC_ADD_X_L(PRE, op, w, n) do {                               \
+  unsigned _i = 0; BLKC_W(w); uint32 _n = (n);                         \
+  while (_i < PRE##_BLKSZ/4 && _n)                                     \
+    { BLKC_ADDC32(op, _w[_i], _n, _w[_i], _n); _i++; }                 \
 } while (0)
 
-#define BLKC_SET_X_B(PRE, w, x) do {                                   \
-  unsigned _i; BLKC_W(w); unsigned long _x = x;                                \
-  for (_i = 0; _i < PRE##_BLKSZ / 4; _i++) {                           \
-    *_w++ = U32(_x);                                                   \
+#define BLKC_BSET_X_B(PRE, w, x) BLKC_SET_X_B(PRE, BLKC_ID, w, x)
+#define BLKC_BSET_X_L(PRE, w, x) BLKC_SET_X_B(PRE, ENDSWAP32, w, x)
+#define BLKC_LSET_X_B(PRE, w, x) BLKC_SET_X_L(PRE, ENDSWAP32, w, x)
+#define BLKC_LSET_X_L(PRE, w, x) BLKC_SET_X_L(PRE, BLKC_ID, w, x)
+
+#define BLKC_SET_X_B(PRE, op, w, x) do {                               \
+  unsigned _i; BLKC_W(w); unsigned long _x = x; _w += PRE##_BLKSZ/4;   \
+  for (_i = 0; _i < PRE##_BLKSZ/4; _i++) {                             \
+    *--_w = U32(op(_x));                                               \
     _x = ((_x & ~(unsigned long)MASK32) >> 16) >> 16;                  \
   }                                                                    \
 } while (0)
 
-#define BLKC_SET_X_L(PRE, w, x) do {                                   \
-  unsigned _i; BLKC_W(w); unsigned long _x = x;        _w += PRE##_BLKSZ / 4;  \
-  for (_i = 0; _i < PRE##_BLKSZ / 4; _i++) {                           \
-    *--_w = U32(_x);                                                   \
+#define BLKC_SET_X_L(PRE, op, w, x) do {                               \
+  unsigned _i; BLKC_W(w); unsigned long _x = x;                                \
+  for (_i = 0; _i < PRE##_BLKSZ/4; _i++) {                             \
+    *_w++ = U32(op(_x));                                               \
     _x = ((_x & ~(unsigned long)MASK32) >> 16) >> 16;                  \
   }                                                                    \
 } while (0)
 
+#define BLKC_BWORD_B(x) (x)
+#define BLKC_BWORD_L(x) ENDSWAP32(x)
+#define BLKC_LWORD_B(x) ENDSWAP32(x)
+#define BLKC_LWORD_L(x) (x)
+
 /* --- Implementation for known block sizes --- */
 
 #define BLKC_SKEL_64(PRE, decl, op, guts)                              \
   BLKC_GLUE(BLKC_SKEL_, n)                                             \
     (PRE, BLKC_W(w); const BLKC_WX(wx);, op, BLKC_XMOVE_GUTS)
 
+/*----- Binary field arithmetic -------------------------------------------*/
+
+#define BLKC_POLY_IRRED64  0x001b
+#define BLKC_POLY_IRRED96  0x0641
+#define BLKC_POLY_IRRED128 0x0087
+#define BLKC_POLY_IRRED192 0x0087
+#define BLKC_POLY_IRRED256 0x0425
+
+#define BLKC_POLY_PRIM64   0x001b
+#define BLKC_POLY_PRIM96   0x0641
+#define BLKC_POLY_PRIM128  0x0087
+#define BLKC_POLY_PRIM192  0x8821
+#define BLKC_POLY_PRIM256  0x0425
+
+#define BLKC_POLY(PRE, f) BLKC_GLUE(BLKC_POLY_##f, BLKC_BITS(PRE))
+
+#define BLKC_BLSHIFT(PRE, f, z, x)                                     \
+  BLKC_GLUE(BLKC_BLSHIFT_X_, BLKC_ENDIAN(PRE))                         \
+    (PRE, f, z, x)
+#define BLKC_LLSHIFT(PRE, f, z, x)                                     \
+  BLKC_GLUE(BLKC_LLSHIFT_X_, BLKC_ENDIAN(PRE))                         \
+    (PRE, f, z, x)
+#define BLKC_LSHIFT(PRE, f, z, x)                                      \
+  BLKC_GLUE(BLKC_LSHIFT_X_, BLKC_ENDIAN(PRE))                          \
+    (PRE, BLKC_ID, f, z, x)
+
+#define BLKC_BRSHIFT(PRE, f, z, x)                                     \
+  BLKC_GLUE(BLKC_BRSHIFT_X_, BLKC_ENDIAN(PRE))                         \
+    (PRE, f, z, x)
+#define BLKC_LRSHIFT(PRE, f, z, x)                                     \
+  BLKC_GLUE(BLKC_LRSHIFT_X_, BLKC_ENDIAN(PRE))                         \
+    (PRE, f, z, x)
+#define BLKC_RSHIFT(PRE, f, z, x)                                      \
+  BLKC_GLUE(BLKC_RSHIFT_X_, BLKC_ENDIAN(PRE))                          \
+    (PRE, BLKC_ID, f, z, x)
+
+#define BLKC_BLSHIFT_X_B(PRE, f, z, x) BLKC_LSHIFT_X_B(PRE, BLKC_ID, f, z, x)
+#define BLKC_LLSHIFT_X_B(PRE, f, z, x) BLKC_LSHIFT_X_L(PRE, ENDSWAP32, f, z, x)
+#define BLKC_BLSHIFT_X_L(PRE, f, z, x) BLKC_LSHIFT_X_B(PRE, ENDSWAP32, f, z, x)
+#define BLKC_LLSHIFT_X_L(PRE, f, z, x) BLKC_LSHIFT_X_L(PRE, BLKC_ID, f, z, x)
+
+#define BLKC_BRSHIFT_X_B(PRE, f, z, x) BLKC_RSHIFT_X_B(PRE, BLKC_ID, f, z, x)
+#define BLKC_LRSHIFT_X_B(PRE, f, z, x) BLKC_RSHIFT_X_L(PRE, ENDSWAP32, f, z, x)
+#define BLKC_BRSHIFT_X_L(PRE, f, z, x) BLKC_RSHIFT_X_B(PRE, ENDSWAP32, f, z, x)
+#define BLKC_LRSHIFT_X_L(PRE, f, z, x) BLKC_RSHIFT_X_L(PRE, BLKC_ID, f, z, x)
+
+#define BLKC_LSHIFT_X_B(PRE, op, f, z, x) do {                         \
+  uint32 *_z = (z); const uint32 *_x = (x);                            \
+  uint32 _t = op(_x[0]), _m = -(uint32)((_t >> 31)&1u),                        \
+    _c = BLKC_POLY(PRE, f)&_m;                                         \
+  unsigned _i;                                                         \
+                                                                       \
+  for (_i = PRE##_BLKSZ/4; _i-- > 0; )                                 \
+    { _t = op(_x[_i]); _z[_i] = op((_t << 1) ^ _c); _c = (_t >> 31)&1u; } \
+} while (0)
+
+#define BLKC_RSHIFT_X_B(PRE, op, f, z, x) do {                         \
+  uint32 *_z = (z); const uint32 *_x = (x);                            \
+  uint32 _t, _t0 = op(_x[PRE##_BLKSZ/4 - 1]), _m = -(uint32)(_t0&1u),  \
+    _c = 0x80000000&_m;                                                        \
+  unsigned _i;                                                         \
+                                                                       \
+  for (_i = 0; _i < PRE##_BLKSZ/4 - 1; _i++)                           \
+    { _t = op(_x[_i]); _z[_i] = op((_t >> 1) ^ _c); _c = (_t&1u) << 31; } \
+  _t0 ^= BLKC_POLY(PRE, f)&_m; _z[PRE##_BLKSZ/4 - 1] = op((_t0 >> 1) ^ _c); \
+} while (0)
+
+#define BLKC_LSHIFT_X_L(PRE, op, f, z, x) do {                         \
+  uint32 *_z = (z); const uint32 *_x = (x);                            \
+  uint32 _t = op(_x[PRE##_BLKSZ/4 - 1]), _m = -(uint32)((_t >> 31)&1u),        \
+    _c = BLKC_POLY(PRE, f)&_m;                                         \
+  unsigned _i;                                                         \
+                                                                       \
+  for (_i = 0; _i < PRE##_BLKSZ/4; _i++)                               \
+    { _t = op(_x[_i]); _z[_i] = op((_t << 1) ^ _c); _c = (_t >> 31)&1u; } \
+} while (0)
+
+#define BLKC_RSHIFT_X_L(PRE, op, f, z, x) do {                         \
+  uint32 *_z = (z); const uint32 *_x = (x);                            \
+  uint32 _t, _t0 = op(_x[0]), _m = -(uint32)(_t0&1u),                  \
+    _c = 0x80000000&_m;                                                        \
+  unsigned _i;                                                         \
+                                                                       \
+  for (_i = PRE##_BLKSZ/4 - 1; _i-- > 1; )                             \
+    { _t = op(_x[_i]); _z[_i] = op((_t >> 1) ^ _c); _c = (_t&1u) << 31; } \
+  _t0 ^= BLKC_POLY(PRE, f)&_m; _z[0] = op((_t0 >> 1) ^ _c);            \
+} while (0)
+
 /*----- Test rig for block ciphers ----------------------------------------*/
 
 /* --- @BLKC_TEST@ --- *
 static int pre##_verify(dstr *v)                                       \
 {                                                                      \
   pre##_ctx k;                                                         \
-  uint32 p[PRE##_BLKSZ / 4];                                           \
-  uint32 c[PRE##_BLKSZ / 4];                                           \
-  uint32 d[PRE##_BLKSZ / 4];                                           \
+  uint32 p[PRE##_BLKSZ/4];                                             \
+  uint32 c[PRE##_BLKSZ/4];                                             \
+  uint32 d[PRE##_BLKSZ/4];                                             \
   dstr b = DSTR_INIT;                                                  \
   int ok = 1;                                                          \
                                                                        \
index 907a5db..480f579 100644 (file)
@@ -81,9 +81,7 @@
  */                                                                    \
                                                                        \
 void pre##_cbcgetiv(const pre##_cbcctx *ctx, void *iv)                 \
-{                                                                      \
-  BLKC_STORE(PRE, iv, ctx->iv);                                                \
-}                                                                      \
+  { BLKC_STORE(PRE, iv, ctx->a); }                                     \
                                                                        \
 /* --- @pre_cbcsetiv@ --- *                                            \
  *                                                                     \
@@ -96,9 +94,7 @@ void pre##_cbcgetiv(const pre##_cbcctx *ctx, void *iv)                        \
  */                                                                    \
                                                                        \
 void pre##_cbcsetiv(pre##_cbcctx *ctx, const void *iv)                 \
-{                                                                      \
-  BLKC_LOAD(PRE, ctx->iv, iv);                                         \
-}                                                                      \
+  { BLKC_LOAD(PRE, ctx->a, iv); }                                      \
                                                                        \
 /* --- @pre_cbcsetkey@ --- *                                           \
  *                                                                     \
@@ -111,9 +107,7 @@ void pre##_cbcsetiv(pre##_cbcctx *ctx, const void *iv)                      \
  */                                                                    \
                                                                        \
 void pre##_cbcsetkey(pre##_cbcctx *ctx, const pre##_ctx *k)            \
-{                                                                      \
-  ctx->ctx = *k;                                                       \
-}                                                                      \
+  { ctx->ctx = *k; }                                                   \
                                                                        \
 /* --- @pre_cbcinit@ --- *                                             \
  *                                                                     \
@@ -131,12 +125,13 @@ void pre##_cbcsetkey(pre##_cbcctx *ctx, const pre##_ctx *k)               \
  */                                                                    \
                                                                        \
 void pre##_cbcinit(pre##_cbcctx *ctx,                                  \
-                    const void *key, size_t sz,                        \
-                    const void *iv)                                    \
+                  const void *key, size_t sz,                          \
+                  const void *iv)                                      \
 {                                                                      \
   static const octet zero[PRE##_BLKSZ] = { 0 };                                \
+                                                                       \
   pre##_init(&ctx->ctx, key, sz);                                      \
-  BLKC_LOAD(PRE, ctx->iv, iv ? iv : zero);                             \
+  BLKC_LOAD(PRE, ctx->a, iv ? iv : zero);                              \
 }                                                                      \
                                                                        \
 /* --- @pre_cbcencrypt@ --- *                                          \
@@ -155,16 +150,18 @@ void pre##_cbcinit(pre##_cbcctx *ctx,                                     \
  */                                                                    \
                                                                        \
 void pre##_cbcencrypt(pre##_cbcctx *ctx,                               \
-                       const void *src, void *dest,                    \
-                       size_t sz)                                      \
+                     const void *src, void *dest,                      \
+                     size_t sz)                                        \
 {                                                                      \
   const octet *s = src;                                                        \
   octet *d = dest;                                                     \
+  octet b[PRE##_BLKSZ], bb[PRE##_BLKSZ];                               \
+  octet y;                                                             \
+  unsigned i;                                                          \
                                                                        \
   /* --- Empty blocks are trivial --- */                               \
                                                                        \
-  if (!sz)                                                             \
-    return;                                                            \
+  if (!sz) return;                                                     \
                                                                        \
   /* --- Extra magical case for a short block --- *                    \
    *                                                                   \
@@ -174,18 +171,13 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                          \
    */                                                                  \
                                                                        \
   if (sz < PRE##_BLKSZ) {                                              \
-    octet b[PRE##_BLKSZ];                                              \
-    unsigned i;                                                                \
-                                                                       \
-    pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
-    BLKC_STORE(PRE, b, ctx->iv);                                       \
-    if (d) {                                                           \
-      for (i = 0; i < sz; i++)                                         \
-       d[i] = b[i] ^ (s ? s[i] : 0);                                   \
-    }                                                                  \
+    pre##_eblk(&ctx->ctx, ctx->a, ctx->a);                             \
+    BLKC_STORE(PRE, b, ctx->a);                                                \
+    if (!d) d = bb;                                                    \
+    for (i = 0; i < sz; i++) d[i] = b[i] ^ (s ? s[i] : 0);             \
     memmove(b, b + sz, PRE##_BLKSZ - sz);                              \
     memcpy(b + PRE##_BLKSZ - sz, d, sz);                               \
-    BLKC_LOAD(PRE, ctx->iv, b);                                                \
+    BLKC_LOAD(PRE, ctx->a, b);                                         \
     return;                                                            \
   }                                                                    \
                                                                        \
@@ -196,16 +188,10 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                          \
    * and keep a copy of the ciphertext for the next block.             \
    */                                                                  \
                                                                        \
-  while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) {                 \
-    if (s) {                                                           \
-      BLKC_XLOAD(PRE, ctx->iv, s);                                     \
-      s += PRE##_BLKSZ;                                                        \
-    }                                                                  \
-    pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
-    if (d) {                                                           \
-      BLKC_STORE(PRE, d, ctx->iv);                                     \
-      d += PRE##_BLKSZ;                                                        \
-    }                                                                  \
+  while (sz >= 2*PRE##_BLKSZ || sz == PRE##_BLKSZ) {                   \
+    if (s) { BLKC_XLOAD(PRE, ctx->a, s); s += PRE##_BLKSZ; }           \
+    pre##_eblk(&ctx->ctx, ctx->a, ctx->a);                             \
+    if (d) { BLKC_STORE(PRE, d, ctx->a); d += PRE##_BLKSZ; }           \
     sz -= PRE##_BLKSZ;                                                 \
   }                                                                    \
                                                                        \
@@ -215,8 +201,6 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                            \
    */                                                                  \
                                                                        \
   if (sz) {                                                            \
-    octet b[PRE##_BLKSZ];                                              \
-    unsigned i;                                                                \
                                                                        \
     /* --- Let @sz@ be the size of the partial block --- */            \
                                                                        \
@@ -230,9 +214,9 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                            \
      * block.                                                          \
      */                                                                        \
                                                                        \
-    if (s) BLKC_XLOAD(PRE, ctx->iv, s);                                        \
-    pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
-    BLKC_STORE(PRE, b, ctx->iv);                                       \
+    if (s) BLKC_XLOAD(PRE, ctx->a, s);                                 \
+    pre##_eblk(&ctx->ctx, ctx->a, ctx->a);                             \
+    BLKC_STORE(PRE, b, ctx->a);                                                \
                                                                        \
     /* --- Second stage --- *                                          \
      *                                                                 \
@@ -244,13 +228,13 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                          \
     if (s) s += PRE##_BLKSZ;                                           \
     if (d) d += PRE##_BLKSZ;                                           \
     for (i = 0; i < sz; i++) {                                         \
-      register octet x = b[i];                                         \
+      y = b[i];                                                                \
       if (s) b[i] ^= s[i];                                             \
-      if (d) d[i] = x;                                                 \
+      if (d) d[i] = y;                                                 \
     }                                                                  \
-    BLKC_LOAD(PRE, ctx->iv, b);                                                \
-    pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
-    if (d) BLKC_STORE(PRE, d - PRE##_BLKSZ, ctx->iv);                  \
+    BLKC_LOAD(PRE, ctx->a, b);                                         \
+    pre##_eblk(&ctx->ctx, ctx->a, ctx->a);                             \
+    if (d) BLKC_STORE(PRE, d - PRE##_BLKSZ, ctx->a);                   \
   }                                                                    \
                                                                        \
   /* --- Done --- */                                                   \
@@ -274,16 +258,19 @@ void pre##_cbcencrypt(pre##_cbcctx *ctx,                          \
  */                                                                    \
                                                                        \
 void pre##_cbcdecrypt(pre##_cbcctx *ctx,                               \
-                       const void *src, void *dest,                    \
-                       size_t sz)                                      \
+                     const void *src, void *dest,                      \
+                     size_t sz)                                        \
 {                                                                      \
   const octet *s = src;                                                        \
   octet *d = dest;                                                     \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ/4];                           \
+  octet b[PRE##_BLKSZ], c[PRE##_BLKSZ];                                        \
+  octet y;                                                             \
+  unsigned i;                                                          \
                                                                        \
   /* --- Empty blocks are trivial --- */                               \
                                                                        \
-  if (!sz)                                                             \
-    return;                                                            \
+  if (!sz) return;                                                     \
                                                                        \
   /* --- Extra magical case for a short block --- *                    \
    *                                                                   \
@@ -293,19 +280,12 @@ void pre##_cbcdecrypt(pre##_cbcctx *ctx,                          \
    */                                                                  \
                                                                        \
   if (sz < PRE##_BLKSZ) {                                              \
-    octet b[PRE##_BLKSZ], c[PRE##_BLKSZ];                              \
-    unsigned i;                                                                \
-                                                                       \
-    pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv);                           \
-    BLKC_STORE(PRE, b, ctx->iv);                                       \
-    for (i = 0; i < sz; i++) {                                         \
-      register octet x = s[i];                                         \
-      d[i] = b[i] ^ x;                                                 \
-      c[i] = x;                                                                \
-    }                                                                  \
+    pre##_eblk(&ctx->ctx, ctx->a, ctx->a);                             \
+    BLKC_STORE(PRE, b, ctx->a);                                                \
+    for (i = 0; i < sz; i++) { y = s[i]; d[i] = b[i] ^ y; c[i] = y; }  \
     memmove(b, b + sz, PRE##_BLKSZ - sz);                              \
     memcpy(b + PRE##_BLKSZ - sz, c, sz);                               \
-    BLKC_LOAD(PRE, ctx->iv, b);                                                \
+    BLKC_LOAD(PRE, ctx->a, b);                                         \
     return;                                                            \
   }                                                                    \
                                                                        \
@@ -316,14 +296,11 @@ void pre##_cbcdecrypt(pre##_cbcctx *ctx,                          \
    * and keep a copy of the ciphertext for the next block.             \
    */                                                                  \
                                                                        \
-  while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) {                 \
-    uint32 b[PRE##_BLKSZ / 4], niv[PRE##_BLKSZ / 4];                   \
-    BLKC_LOAD(PRE, niv, s);                                            \
-    pre##_dblk(&ctx->ctx, niv, b);                                     \
-    BLKC_XSTORE(PRE, d, b, ctx->iv);                                   \
-    BLKC_MOVE(PRE, ctx->iv, niv);                                      \
-    s += PRE##_BLKSZ;                                                  \
-    d += PRE##_BLKSZ;                                                  \
+  while (sz >= 2*PRE##_BLKSZ || sz == PRE##_BLKSZ) {                   \
+    BLKC_LOAD(PRE, t, s); s += PRE##_BLKSZ;                            \
+    pre##_dblk(&ctx->ctx, t, u);                                       \
+    BLKC_XSTORE(PRE, d, u, ctx->a); d += PRE##_BLKSZ;                  \
+    BLKC_MOVE(PRE, ctx->a, t);                                         \
     sz -= PRE##_BLKSZ;                                                 \
   }                                                                    \
                                                                        \
@@ -333,9 +310,6 @@ void pre##_cbcdecrypt(pre##_cbcctx *ctx,                            \
    */                                                                  \
                                                                        \
   if (sz) {                                                            \
-    octet b[PRE##_BLKSZ];                                              \
-    uint32 bk[PRE##_BLKSZ / 4], niv[PRE##_BLKSZ / 4];                  \
-    unsigned i;                                                                \
                                                                        \
     /* --- Let @sz@ be the size of the partial block --- */            \
                                                                        \
@@ -347,8 +321,8 @@ void pre##_cbcdecrypt(pre##_cbcctx *ctx,                            \
      * is carried over for the next encryption operation.              \
      */                                                                        \
                                                                        \
-    BLKC_LOAD(PRE, niv, s);                                            \
-    pre##_dblk(&ctx->ctx, niv, bk);                                    \
+    BLKC_LOAD(PRE, t, s);                                              \
+    pre##_dblk(&ctx->ctx, t, u);                                       \
                                                                        \
     /* --- Second stage --- *                                          \
      *                                                                 \
@@ -358,14 +332,10 @@ void pre##_cbcdecrypt(pre##_cbcctx *ctx,                          \
      * three.                                                          \
      */                                                                        \
                                                                        \
-    BLKC_STORE(PRE, b, bk);                                            \
+    BLKC_STORE(PRE, b, u);                                             \
     s += PRE##_BLKSZ;                                                  \
     d += PRE##_BLKSZ;                                                  \
-    for (i = 0; i < sz; i++) {                                         \
-      register octet x = s[i];                                         \
-      d[i] = b[i] ^ x;                                                 \
-      b[i] = x;                                                                \
-    }                                                                  \
+    for (i = 0; i < sz; i++) { y = s[i]; d[i] = b[i] ^ y; b[i] = y; }  \
                                                                        \
     /* --- Third stage --- *                                           \
      *                                                                 \
@@ -373,10 +343,10 @@ void pre##_cbcdecrypt(pre##_cbcctx *ctx,                          \
      * recover the complete plaintext block.                           \
      */                                                                        \
                                                                        \
-    BLKC_LOAD(PRE, bk, b);                                             \
-    pre##_dblk(&ctx->ctx, bk, bk);                                     \
-    BLKC_XSTORE(PRE, d - PRE##_BLKSZ, bk, ctx->iv);                    \
-    BLKC_MOVE(PRE, ctx->iv, niv);                                      \
+    BLKC_LOAD(PRE, u, b);                                              \
+    pre##_dblk(&ctx->ctx, u, u);                                       \
+    BLKC_XSTORE(PRE, d - PRE##_BLKSZ, u, ctx->a);                      \
+    BLKC_MOVE(PRE, ctx->a, t);                                         \
   }                                                                    \
                                                                        \
   /* --- Done --- */                                                   \
@@ -402,29 +372,16 @@ static gcipher *ginit(const void *k, size_t sz)                           \
 }                                                                      \
                                                                        \
 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_cbcencrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_cbcencrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdecrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_cbcdecrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_cbcdecrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdestroy(gcipher *c)                                       \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  BURN(*g);                                                            \
-  S_DESTROY(g);                                                                \
-}                                                                      \
+  { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }                     \
                                                                        \
 static void gsetiv(gcipher *c, const void *iv)                         \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_cbcsetiv(&g->k, iv);                                           \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_cbcsetiv(&g->k, iv); }                  \
                                                                        \
 static const gcipher_ops gops = {                                      \
   &pre##_cbc,                                                          \
@@ -444,9 +401,7 @@ CBC_TESTX(PRE, pre, name, fname)
 
 #ifdef TEST_RIG
 
-#include <stdio.h>
-
-#include "daftstory.h"
+#include "modes-test.h"
 
 /* --- @CBC_TEST@ --- *
  *
@@ -457,85 +412,28 @@ CBC_TESTX(PRE, pre, name, fname)
 
 #define CBC_TESTX(PRE, pre, name, fname)                               \
                                                                        \
-/* --- Initial plaintext for the test --- */                           \
-                                                                       \
-static const octet text[] = TEXT;                                      \
+static pre##_ctx key;                                                  \
+static pre##_cbcctx ctx;                                               \
                                                                        \
-/* --- Key and IV to use --- */                                                \
+static void pre##_cbc_test_setup(const octet *k, size_t ksz)           \
+  { pre##_init(&key, k, ksz); pre##_cbcsetkey(&ctx, &key); }           \
                                                                        \
-static const octet key[] = KEY;                                                \
-static const octet iv[] = IV;                                          \
+static void pre##_cbc_test_reset(const octet *iv)                      \
+  { pre##_cbcsetiv(&ctx, iv); }                                                \
                                                                        \
-/* --- Buffers for encryption and decryption output --- */             \
+static void pre##_cbc_test_enc(const octet *s, octet *d, size_t sz)    \
+  { pre##_cbcencrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-static octet ct[sizeof(text)];                                         \
-static octet pt[sizeof(text)];                                         \
+static void pre##_cbc_test_dec(const octet *s, octet *d, size_t sz)    \
+  { pre##_cbcdecrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-static void hexdump(const octet *p, size_t sz, size_t off)             \
+int main(int argc, char *argv[])                                       \
 {                                                                      \
-  const octet *q = p + sz;                                             \
-  for (sz = 0; p < q; p++, sz++) {                                     \
-    printf("%02x", *p);                                                        \
-    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
-      putchar(':');                                                    \
-  }                                                                    \
-}                                                                      \
-                                                                       \
-int main(void)                                                         \
-{                                                                      \
-  size_t sz = 0, rest;                                                 \
-  pre##_cbcctx ctx;                                                    \
-  pre##_ctx k;                                                         \
-  int status = 0;                                                      \
-  int done = 0;                                                                \
-                                                                       \
-  size_t keysz = PRE##_KEYSZ ?                                         \
-    PRE##_KEYSZ : strlen((const char *)key);                           \
-                                                                       \
-  fputs(name "-cbc: ", stdout);                                                \
-                                                                       \
-  pre##_init(&k, key, keysz);                                          \
-  pre##_cbcsetkey(&ctx, &k);                                           \
-                                                                       \
-  while (sz <= sizeof(text)) {                                         \
-    rest = sizeof(text) - sz;                                          \
-    memcpy(ct, text, sizeof(text));                                    \
-    pre##_cbcsetiv(&ctx, iv);                                          \
-    pre##_cbcencrypt(&ctx, ct, ct, sz);                                        \
-    pre##_cbcencrypt(&ctx, ct + sz, ct + sz, rest);                    \
-    memcpy(pt, ct, sizeof(text));                                      \
-    pre##_cbcsetiv(&ctx, iv);                                          \
-    pre##_cbcdecrypt(&ctx, pt, pt, sz);                                        \
-    pre##_cbcdecrypt(&ctx, pt + sz, pt + sz, rest);                    \
-    if (memcmp(pt, text, sizeof(text)) == 0) {                         \
-      done++;                                                          \
-      if (sizeof(text) < 40 || done % 8 == 0)                          \
-       fputc('.', stdout);                                             \
-      if (done % 480 == 0)                                             \
-       fputs("\n\t", stdout);                                          \
-      fflush(stdout);                                                  \
-    } else {                                                           \
-      printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
-      status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
-       printf(", "); hexdump(text + sz, rest, sz);                     \
-       fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
-       printf(", "); hexdump(ct + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
-       printf(", "); hexdump(pt + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      fputc('\n', stdout);                                             \
-    }                                                                  \
-    if (sz < 63)                                                       \
-      sz++;                                                            \
-    else                                                               \
-      sz += 9;                                                         \
-  }                                                                    \
-                                                                       \
-  fputs(status ? " failed\n" : " ok\n", stdout);                       \
-  return (status);                                                     \
+  return test_encmode(fname "-cbc", PRE##_KEYSZ, PRE##_BLKSZ,          \
+                     1, TEMF_REFALIGN,                                 \
+                     pre##_cbc_test_setup, pre##_cbc_test_reset,       \
+                     pre##_cbc_test_enc, pre##_cbc_test_dec,           \
+                     argc, argv);                                      \
 }
 
 #else
index 5f1f22a..7b21eea 100644 (file)
@@ -57,7 +57,7 @@
                                                                        \
 typedef struct pre##_cbcctx {                                          \
   pre##_ctx ctx;                       /* Underlying cipher context */ \
-  uint32 iv[PRE##_BLKSZ / 4];          /* Previous ciphertext or IV */ \
+  uint32 a[PRE##_BLKSZ/4];             /* Previous ciphertext or IV */ \
 } pre##_cbcctx;                                                                \
                                                                        \
 /* --- @pre_cbcgetiv@ --- *                                            \
diff --git a/symm/ccm-def.h b/symm/ccm-def.h
new file mode 100644 (file)
index 0000000..2d864fa
--- /dev/null
@@ -0,0 +1,902 @@
+/* -*-c-*-
+ *
+ * The CCM authenticated-encryption mode
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_CCM_DEF_H
+#define CATACOMB_CCM_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_BLKC_H
+#  include "blkc.h"
+#endif
+
+#ifndef CATACOMB_CT_H
+#  include "ct.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+#  include "keysz.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+/*----- Common machinery --------------------------------------------------*/
+
+/* --- @ccm_check@ --- *
+ *
+ * Arguments:  @const ccm_params *p@ = pointer to parameters
+ *
+ * Returns:    True (nonzero) if the parameters are OK; false (zero) if
+ *             there's a problem.
+ *
+ * Use:                Verify that the CCM parameters are acceptable.
+ */
+
+extern int ccm_check(const ccm_params */*p*/);
+
+/* --- @ccm_fmthdr@ --- *
+ *
+ * Arguments:  @const ccm_params *p@ = pointer to parameters
+ *             @octet *b@ = block-size buffer to write header
+ *             @const void *n@ = pointer to nonce
+ *
+ * Returns:    ---
+ *
+ * Use:                Format a MAC header block.
+ */
+
+extern void ccm_fmthdr(const ccm_params */*p*/,
+                      octet */*b*/, const void */*n*/);
+
+/* --- @ccm_fmtctr@ --- *
+ *
+ * Arguments:  @const ccm_params *p@ = pointer to parameters
+ *             @octet *b@ = block-size buffer to write header
+ *             @const void *n@ = pointer to nonce
+ *
+ * Returns:    ---
+ *
+ * Use:                Format an initial counter block.
+ */
+
+extern void ccm_fmtctr(const ccm_params */*p*/,
+                      octet */*b*/, const void */*n*/);
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @CCM_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates an implementation for the CCM authenticated-
+ *             encryption mode.
+ */
+
+#define CCM_DEF(PRE, pre) CCM_DEFX(PRE, pre, #pre, #pre)
+
+#define CCM_DEFX(PRE, pre, name, fname)                                        \
+                                                                       \
+const octet pre##_ccmnoncesz[] =                                       \
+  { KSZ_RANGE, PRE##_BLKSZ/2 - (PRE##_BLKSZ <= 16 ? 1 : 2),            \
+    CCM_NSZMIN(PRE), CCM_NSZMAX(PRE), 1 };                             \
+const octet pre##_ccmtagsz[] =                                         \
+  { KSZ_RANGE, CCM_TSZMAX(PRE),                                                \
+    CCM_TSZMIN(PRE), CCM_TSZMAX(PRE), PRE##_BLKSZ == 16 ? 2 : 1 };     \
+                                                                       \
+static const rsvr_policy pre##_ccmpolicy =                             \
+  { RSVRF_FULL, PRE##_BLKSZ, PRE##_BLKSZ };                            \
+                                                                       \
+/* --- @pre_ccminthash@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to context block            \
+ *             @const void *p@ = pointer to material to hash           \
+ *             @size_t sz@ = size of the input buffer                  \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Internal operation for feeding stuff into the CBC-MAC   \
+ *             context.                                                \
+ */                                                                    \
+                                                                       \
+static void pre##_ccminthash(pre##_ccmctx *ctx,                                \
+                            const void *p, size_t sz)                  \
+{                                                                      \
+  rsvr_state st;                                                       \
+  const octet *q;                                                      \
+                                                                       \
+  rsvr_setup(&st, &pre##_ccmpolicy, ctx->b, &ctx->off, p, sz);         \
+  RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    BLKC_XLOAD(PRE, ctx->a, q);                                                \
+    pre##_eblk(&ctx->k, ctx->a, ctx->a);                               \
+  }                                                                    \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccminit@ --- *                                             \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *aad@ = pointer to CCM context              \
+ *             @const pre_ctx *k@ = pointer to key material            \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of the nonce                        \
+ *             @size_t hsz@ = size of the AAD                          \
+ *             @size_t msz@ = size of the message/ciphertext           \
+ *             @size_t tsz@ = size of the tag to produce               \
+ *                                                                     \
+ * Returns:    Zero on success; nonzero if the parameters are invalid. \
+ *                                                                     \
+ * Use:                Initialize an CCM operation context with a given key.   \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+int pre##_ccminit(pre##_ccmctx *ctx, const pre##_ctx *k,               \
+                 const void *n, size_t nsz,                            \
+                 size_t hsz, size_t msz, size_t tsz)                   \
+  { ctx->k = *k; return (pre##_ccmreinit(ctx, n, nsz, hsz, msz, tsz)); } \
+                                                                       \
+/* --- @pre_ccmreinit@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to CCM context              \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *             @size_t hsz@ = size of the AAD                          \
+ *             @size_t msz@ = size of the message/ciphertext           \
+ *             @size_t tsz@ = size of the tag to produce               \
+ *                                                                     \
+ * Returns:    Zero on success; nonzero if the parameters are invalid. \
+ *                                                                     \
+ * Use:                Reinitialize an CCM operation context, changing the     \
+ *             nonce.                                                  \
+ */                                                                    \
+                                                                       \
+int pre##_ccmreinit(pre##_ccmctx *ctx, const void *n, size_t nsz,      \
+                   size_t hsz, size_t msz, size_t tsz)                 \
+{                                                                      \
+  kludge64 t;                                                          \
+  octet b[12];                                                         \
+  size_t sz;                                                           \
+                                                                       \
+  /* Set up the parameters and check that they make sense. */          \
+  ctx->p.hsz = hsz; ctx->p.msz = msz;                                  \
+  ctx->p.bsz = PRE##_BLKSZ; ctx->p.nsz = nsz; ctx->p.tsz = tsz;                \
+  if (!ccm_check(&ctx->p)) return (-1);                                        \
+                                                                       \
+  /* Prepare the counter and the final MAC mask.  The initial counter  \
+   * is used to make the MAC mask, so generate that, keeping it for    \
+   * later.                                                            \
+   */                                                                  \
+  ccm_fmtctr(&ctx->p, ctx->b, n);                                      \
+  BLKC_LOAD(PRE, ctx->c, ctx->b);                                      \
+  pre##_eblk(&ctx->k, ctx->c, ctx->s0);                                        \
+                                                                       \
+  /* Prepare the MAC header and leave it in the buffer. */             \
+  ccm_fmthdr(&ctx->p, ctx->b, n);                                      \
+  BLKC_ZERO(PRE, ctx->a);                                              \
+                                                                       \
+  /* Initialize our state.  The buffer is currently full (with the     \
+   * MAC header), and we're always awaiting AAD, though we've not yet  \
+   * seen any.  (Even if we're not expecting AAD, this will trigger    \
+   * appropriate initialization when encryption or decryption begins.) \
+   */                                                                  \
+  ctx->off = PRE##_BLKSZ; ctx->i = 0;                                  \
+  ctx->st = CCMST_AAD;                                                 \
+                                                                       \
+  /* If there's AAD to come, then do the AAD framing.  This aligns     \
+   * badly with the blocking, so feed the framing in the hard way.     \
+   */                                                                  \
+  if (hsz) {                                                           \
+    if (hsz < 0xfffe)                                                  \
+      { STORE16(b, hsz); sz = 2; }                                     \
+    else if (hsz <= MASK32)                                            \
+      { b[0] = 0xff; b[1] = 0xfe; STORE32(b + 2, hsz); sz = 6; }       \
+    else {                                                             \
+      b[0] = b[1] = 0xff;                                              \
+      ASSIGN64(t, hsz); STORE64_(b + 2, t);                            \
+      sz = 10;                                                         \
+    }                                                                  \
+    pre##_ccminthash(ctx, b, sz);                                      \
+  }                                                                    \
+                                                                       \
+  /* All done. */                                                      \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccmaadhash@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to AAD context              \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.  This must be done before   \
+ *             any of the message/ciphertext is processed because CCM  \
+ *             is really annoying like that.                           \
+ */                                                                    \
+                                                                       \
+void pre##_ccmaadhash(pre##_ccmctx *ctx, const void *p, size_t sz)     \
+{                                                                      \
+  assert(ctx->st == CCMST_AAD);                                                \
+  assert(sz <= ctx->p.hsz - ctx->i);                                   \
+  ctx->i += sz;                                                                \
+  pre##_ccminthash(ctx, p, sz);                                                \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccmencdecsetup@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to context block            \
+ *             @size_t sz@ = size of message block                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Prepares for an encrypt or decryption operation,        \
+ *             transitioning from the AAD state and updating the       \
+ *             message size.                                           \
+ */                                                                    \
+                                                                       \
+static void pre##_ccmencdecsetup(pre##_ccmctx *ctx, size_t sz)         \
+{                                                                      \
+  if (ctx->st != CCMST_MSG) {                                          \
+    /* Make sure we're currently in the AAD state and we've seen all of        \
+     * the AAD we expected.                                            \
+     */                                                                        \
+    assert(ctx->st == CCMST_AAD);                                      \
+    assert(ctx->i == ctx->p.hsz);                                      \
+                                                                       \
+    /* Pad the final AAD block out until we hit a block boundary.  Note        \
+     * that we don't cycle the block cipher here: instead, leave the   \
+     * buffer full so that we do that next time.                       \
+     */                                                                        \
+    memset(ctx->b + ctx->off, 0, PRE##_BLKSZ - ctx->off);              \
+    ctx->off = PRE##_BLKSZ;                                            \
+                                                                       \
+    /* Now we're ready to process the message text. */                 \
+    ctx->st = CCMST_MSG; ctx->i = 0;                                   \
+  }                                                                    \
+                                                                       \
+  /* Update the size. */                                               \
+  assert(sz <= ctx->p.msz - ctx->i);                                   \
+  ctx->i += sz;                                                                \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccmencrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to CCM operation context    \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For CCM, we always write a ciphertext chunk the same    \
+ *             size as the plaintext.  The messing about with @buf@    \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+int pre##_ccmencrypt(pre##_ccmctx *ctx,                                        \
+                    const void *src, size_t sz, buf *dst)              \
+{                                                                      \
+  rsvr_plan plan;                                                      \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ];                             \
+  const octet *p = src;                                                        \
+  octet *q, *r, y;                                                     \
+                                                                       \
+  /* Allocate space for the ciphertext. */                             \
+  if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+                                                                       \
+  /* Set stuff up. */                                                  \
+  pre##_ccmencdecsetup(ctx, sz);                                       \
+                                                                       \
+  /* Determine the buffering plan.  Our buffer is going to do double-  \
+   * duty here.  The end portion is going to contain mask from the     \
+   * encrypted counter which we mix into the plaintext to encrypt it;  \
+   * the start portion, which originally mask bytes we've already used,        \
+   * will hold the input plaintext, which will eventually be           \
+   * collected into the CBC-MAC state.                                 \
+   */                                                                  \
+  rsvr_mkplan(&plan, &pre##_ccmpolicy, ctx->off, sz);                  \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the buffer is     \
+   * empty, then that means that we haven't yet encrypted the current  \
+   * counter, so we should do that and advance it.                     \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);         \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
+    }                                                                  \
+    r = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    while (plan.head--) { y = *p++; *q++ = y ^ *r; *r++ = y; }         \
+  }                                                                    \
+                                                                       \
+  /* If we've filled up the buffer then we need to cycle the MAC and   \
+   * reset the offset.                                                 \
+   */                                                                  \
+  if (plan.from_rsvr) {                                                        \
+    BLKC_XLOAD(PRE, ctx->a, ctx->b);                                   \
+    pre##_eblk(&ctx->k, ctx->a, ctx->a);                               \
+    ctx->off = 0;                                                      \
+  }                                                                    \
+                                                                       \
+  /* Now to process the main body of the input. */                     \
+  while (plan.from_input) {                                            \
+    BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);           \
+    BLKC_LOAD(PRE, u, p); p += PRE##_BLKSZ;                            \
+    BLKC_XSTORE(PRE, q, t, u); q += PRE##_BLKSZ;                       \
+    BLKC_XMOVE(PRE, ctx->a, u); pre##_eblk(&ctx->k, ctx->a, ctx->a);   \
+    plan.from_input -= PRE##_BLKSZ;                                    \
+  }                                                                    \
+                                                                       \
+  /* Finally, deal with any final portion.  If there is one, we know   \
+   * that the buffer is empty: we must have filled it above, or this   \
+   * would all count as `initial' data.                                        \
+   */                                                                  \
+  if (plan.tail) {                                                     \
+    BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);           \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    r = ctx->b; ctx->off = plan.tail;                                  \
+    while (plan.tail--) { y = *p++; *q++ = y ^ *r; *r++ = y; }         \
+  }                                                                    \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccmdecrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to CCM operation context    \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For CCM, we always write a plaintext chunk the same     \
+ *             size as the ciphertext.  The messing about with @buf@   \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+int pre##_ccmdecrypt(pre##_ccmctx *ctx,                                        \
+                    const void *src, size_t sz, buf *dst)              \
+{                                                                      \
+  rsvr_plan plan;                                                      \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *p = src;                                                        \
+  octet *q, *r, y;                                                     \
+                                                                       \
+  /* Allocate space for the plaintext. */                              \
+  if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+                                                                       \
+  /* Set stuff up. */                                                  \
+  pre##_ccmencdecsetup(ctx, sz);                                       \
+                                                                       \
+  /* Determine the buffering plan.  Our buffer is going to do double-  \
+   * duty here.  The end portion is going to contain mask from the     \
+   * encrypted counter which we mix into the plaintext to encrypt it;  \
+   * the start portion, which originally mask bytes we've already used,        \
+   * will hold the recovered plaintext, which will eventually be       \
+   * collected into the CBC-MAC state.                                 \
+   */                                                                  \
+  rsvr_mkplan(&plan, &pre##_ccmpolicy, ctx->off, sz);                  \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the buffer is     \
+   * empty, then that means that we haven't yet encrypted the current  \
+   * counter, so we should do that and advance it.                     \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);         \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
+    }                                                                  \
+    r = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    while (plan.head--) { y = *p++ ^ *r; *q++ = *r++ = y; }            \
+  }                                                                    \
+                                                                       \
+  /* If we've filled up the buffer then we need to cycle the MAC and   \
+   * reset the offset.                                                 \
+   */                                                                  \
+  if (plan.from_rsvr) {                                                        \
+    BLKC_XLOAD(PRE, ctx->a, ctx->b);                                   \
+    pre##_eblk(&ctx->k, ctx->a, ctx->a);                               \
+    ctx->off = 0;                                                      \
+  }                                                                    \
+                                                                       \
+  /* Now to process the main body of the input. */                     \
+  while (plan.from_input) {                                            \
+    BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);           \
+    BLKC_XLOAD(PRE, t, p); p += PRE##_BLKSZ;                           \
+    BLKC_STORE(PRE, q, t); q += PRE##_BLKSZ;                           \
+    BLKC_XMOVE(PRE, ctx->a, t); pre##_eblk(&ctx->k, ctx->a, ctx->a);   \
+    plan.from_input -= PRE##_BLKSZ;                                    \
+  }                                                                    \
+                                                                       \
+  /* Finally, deal with any final portion.  If there is one, we know   \
+   * that the buffer is empty: we must have filled it above, or this   \
+   * would all count as `initial' data.                                        \
+   */                                                                  \
+  if (plan.tail) {                                                     \
+    BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);           \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    r = ctx->b; ctx->off = plan.tail;                                  \
+    while (plan.tail--) { y = *p++ ^ *r; *q++ = *r++ = y; }            \
+  }                                                                    \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccmtag@ --- *                                              \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to an CCM context           \
+ *             @octet *t@ = where to write a (full-length) tag         \
+ *             @size_t tsz@ = size of the tag (to check)               \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes an CCM operation, by calculating the tag.      \
+ */                                                                    \
+                                                                       \
+static void pre##_ccmtag(pre##_ccmctx *ctx, octet *t, size_t tsz)      \
+{                                                                      \
+  /* Make sure we're in good shape.  It's just about possible that     \
+   * we're still in the AAD state, but there was no actual message, so \
+   * handle this situation.                                            \
+   */                                                                  \
+  switch (ctx->st) {                                                   \
+    case CCMST_AAD:                                                    \
+      assert(ctx->i == ctx->p.hsz);                                    \
+      assert(!ctx->p.msz);                                             \
+      break;                                                           \
+    case CCMST_MSG:                                                    \
+      /* hsz already checked in `pre_ccmencdecsetup'. */               \
+      assert(ctx->i == ctx->p.msz);                                    \
+      break;                                                           \
+    default: abort();                                                  \
+  }                                                                    \
+  assert(tsz == ctx->p.tsz);                                           \
+                                                                       \
+  /* Pad the final plaintext block out and cycle the block cipher one  \
+   * last time.                                                                \
+   */                                                                  \
+  memset(ctx->b + ctx->off, 0, PRE##_BLKSZ - ctx->off);                        \
+  BLKC_XLOAD(PRE, ctx->a, ctx->b);                                     \
+  pre##_eblk(&ctx->k, ctx->a, ctx->a);                                 \
+                                                                       \
+  /* Mask the CBC-MAC tag (which prevents the standard extension       \
+   * attack) and store the result.                                     \
+   */                                                                  \
+  BLKC_XSTORE(PRE, t, ctx->a, ctx->s0);                                        \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccmencryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to an CCM context           \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an CCM encryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  CCM doesn't buffer ciphertext, but \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+int pre##_ccmencryptdone(pre##_ccmctx *ctx, buf *dst,                  \
+                        void *tag, size_t tsz)                         \
+{                                                                      \
+  octet t[PRE##_BLKSZ];                                                        \
+                                                                       \
+  /* Some initial checks. */                                           \
+  if (!BOK(dst)) return (-1);                                          \
+                                                                       \
+  /* Calculate and return the tag. */                                  \
+  pre##_ccmtag(ctx, t, tsz);                                           \
+  memcpy(tag, t, tsz);                                                 \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ccmdecryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to an CCM context           \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an CCM decryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  CCM doesn't buffer plaintext, but  \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+int pre##_ccmdecryptdone(pre##_ccmctx *ctx, buf *dst,                  \
+                        const void *tag, size_t tsz)                   \
+{                                                                      \
+  octet t[PRE##_BLKSZ];                                                        \
+                                                                       \
+  /* Some initial checks. */                                           \
+  if (!BOK(dst)) return (-1);                                          \
+                                                                       \
+  /* Calculate and check the tag. */                                   \
+  pre##_ccmtag(ctx, t, tsz);                                           \
+  if (!ct_memeq(tag, t, tsz)) return (0);                              \
+  else return (+1);                                                    \
+}                                                                      \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+typedef struct gctx {                                                  \
+  gaead_aad a;                                                         \
+  pre##_ccmctx ctx;                                                    \
+} gctx;                                                                        \
+                                                                       \
+static void gahash(gaead_aad *a, const void *h, size_t hsz)            \
+  { gctx *ctx = (gctx *)a; pre##_ccmaadhash(&ctx->ctx, h, hsz); }      \
+                                                                       \
+static void gadestroy(gaead_aad *a) { ; }                              \
+                                                                       \
+static const gaead_aadops gaops =                                      \
+  { &pre##_ccm, 0, gahash, gadestroy };                                        \
+                                                                       \
+typedef struct gectx {                                                 \
+  gaead_enc e;                                                         \
+  gctx g;                                                              \
+} gectx;                                                               \
+                                                                       \
+static gaead_aad *geaad(gaead_enc *e)                                  \
+  { gectx *enc = (gectx *)e; return (&enc->g.a); }                     \
+                                                                       \
+static int gereinit(gaead_enc *e, const void *n, size_t nsz,           \
+                   size_t hsz, size_t msz, size_t tsz)                 \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_ccmreinit(&enc->g.ctx, n, nsz, hsz, msz, tsz));                \
+}                                                                      \
+                                                                       \
+static int geenc(gaead_enc *e, const void *m, size_t msz, buf *b)      \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_ccmencrypt(&enc->g.ctx, m, msz, b));                   \
+}                                                                      \
+                                                                       \
+static int gedone(gaead_enc *e, const gaead_aad *a,                    \
+                 buf *b, void *t, size_t tsz)                          \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  assert((!a && !enc->g.ctx.p.hsz) || a == &enc->g.a);                 \
+  return (pre##_ccmencryptdone(&enc->g.ctx, b, t, tsz));               \
+}                                                                      \
+                                                                       \
+static void gedestroy(gaead_enc *e)                                    \
+  { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); }             \
+                                                                       \
+static const gaead_encops geops =                                      \
+  { &pre##_ccm, geaad, gereinit, geenc, gedone, gedestroy };           \
+                                                                       \
+typedef struct gdctx {                                                 \
+  gaead_dec d;                                                         \
+  gctx g;                                                              \
+} gdctx;                                                               \
+                                                                       \
+static gaead_aad *gdaad(gaead_dec *d)                                  \
+  { gdctx *dec = (gdctx *)d; return (&dec->g.a); }                     \
+                                                                       \
+static int gdreinit(gaead_dec *d, const void *n, size_t nsz,           \
+                   size_t hsz, size_t csz, size_t tsz)                 \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_ccmreinit(&dec->g.ctx, n, nsz, hsz, csz, tsz));                \
+}                                                                      \
+                                                                       \
+static int gddec(gaead_dec *d, const void *c, size_t csz, buf *b)      \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_ccmdecrypt(&dec->g.ctx, c, csz, b));                   \
+}                                                                      \
+                                                                       \
+static int gddone(gaead_dec *d, const gaead_aad *a,                    \
+                 buf *b, const void *t, size_t tsz)                    \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  assert((!a && !dec->g.ctx.p.hsz) || a == &dec->g.a);                 \
+  return (pre##_ccmdecryptdone(&dec->g.ctx, b, t, tsz));               \
+}                                                                      \
+                                                                       \
+static void gddestroy(gaead_dec *d)                                    \
+  { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); }             \
+                                                                       \
+static const gaead_decops gdops =                                      \
+  { &pre##_ccm, gdaad, gdreinit, gddec, gddone, gddestroy };           \
+                                                                       \
+typedef struct gkctx {                                                 \
+  gaead_key k;                                                         \
+  pre##_ctx key;                                                       \
+} gkctx;                                                               \
+                                                                       \
+static gaead_enc *gkenc(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t msz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gectx *enc = S_CREATE(gectx);                                                \
+                                                                       \
+  enc->e.ops = &geops; enc->g.a.ops = &gaops;                          \
+  if (pre##_ccminit(&enc->g.ctx, &key->key, n, nsz, hsz, msz, tsz))    \
+    { gedestroy(&enc->e); return (0); }                                        \
+  return (&enc->e);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_dec *gkdec(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t csz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gdctx *dec = S_CREATE(gdctx);                                                \
+                                                                       \
+  dec->d.ops = &gdops; dec->g.a.ops = &gaops;                          \
+  if (pre##_ccminit(&dec->g.ctx, &key->key, n, nsz, hsz, csz, tsz))    \
+    { gddestroy(&dec->d); return (0); }                                        \
+  return (&dec->d);                                                    \
+}                                                                      \
+                                                                       \
+static void gkdestroy(gaead_key *k)                                    \
+  { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); }             \
+                                                                       \
+static const gaead_keyops gkops =                                      \
+  { &pre##_ccm, 0, gkenc, gkdec, gkdestroy };                          \
+                                                                       \
+static gaead_key *gckey(const void *k, size_t ksz)                     \
+{                                                                      \
+  gkctx *key = S_CREATE(gkctx);                                                \
+  key->k.ops = &gkops;                                                 \
+  pre##_init(&key->key, k, ksz);                                       \
+  return (&key->k);                                                    \
+}                                                                      \
+                                                                       \
+const gcaead pre##_ccm = {                                             \
+  name "-ccm",                                                         \
+  pre##_keysz, pre##_ccmnoncesz, pre##_ccmtagsz,                       \
+  PRE##_BLKSZ, 0, 0,                                                   \
+  AEADF_PCHSZ | AEADF_PCMSZ | AEADF_PCTSZ |                            \
+  AEADF_AADNDEP | AEADF_AADFIRST,                                      \
+  gckey                                                                        \
+};                                                                     \
+                                                                       \
+CCM_TESTX(PRE, pre, name, fname)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#define CCM_TEST(PRE, pre) CCM_TESTX(PRE, pre, #pre, #pre)
+
+/* --- @CCM_TEST@ --- *
+ *
+ * Arguments:  @PRE, pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Standard test rig for CCM functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define CCM_TESTX(PRE, pre, name, fname)                               \
+                                                                       \
+static int ccmverify(dstr *v)                                          \
+{                                                                      \
+  pre##_ctx key;                                                       \
+  pre##_ccmctx ctx;                                                    \
+  int ok = 1, win;                                                     \
+  int i;                                                               \
+  octet *p;                                                            \
+  int szs[] = { 1, 7, 192, -1, 0 }, *ip;                               \
+  size_t hsz, msz;                                                     \
+  dstr d = DSTR_INIT, t = DSTR_INIT;                                   \
+  buf b;                                                               \
+                                                                       \
+  dstr_ensure(&d, v[4].len > v[3].len ? v[4].len : v[3].len);          \
+  dstr_ensure(&t, v[5].len); t.len = v[5].len;                         \
+                                                                       \
+  pre##_init(&key, v[0].buf, v[0].len);                                        \
+                                                                       \
+  for (ip = szs; *ip; ip++) {                                          \
+                                                                       \
+    pre##_ccminit(&ctx, &key, (octet *)v[1].buf, v[1].len,             \
+                 v[2].len, v[3].len, v[5].len);                        \
+                                                                       \
+    i = *ip;                                                           \
+    hsz = v[2].len;                                                    \
+    if (i == -1) i = hsz;                                              \
+    if (i > hsz) continue;                                             \
+    p = (octet *)v[2].buf;                                             \
+    while (hsz) {                                                      \
+      if (i > hsz) i = hsz;                                            \
+      pre##_ccmaadhash(&ctx, p, i);                                    \
+      p += i; hsz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[3].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[3].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_ccmencrypt(&ctx, p, i, &b)) {                          \
+       puts("!! ccmencrypt reports failure");                          \
+       goto fail_enc;                                                  \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    if (pre##_ccmencryptdone(&ctx, &b, (octet *)t.buf, t.len)) {       \
+      puts("!! ccmencryptdone reports failure");                       \
+      goto fail_enc;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[4].len ||                                           \
+       memcmp(d.buf, v[4].buf, v[4].len) != 0 ||                       \
+       memcmp(t.buf, v[5].buf, v[5].len) != 0) {                       \
+    fail_enc:                                                          \
+      printf("\nfail encrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tmessage = ", stdout); type_hex.dump(&v[3], stdout);   \
+      fputs("\n\texp ct = ", stdout); type_hex.dump(&v[4], stdout);    \
+      fputs("\n\tcalc ct = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\texp tag = ", stdout); type_hex.dump(&v[5], stdout);   \
+      fputs("\n\tcalc tag = ", stdout); type_hex.dump(&t, stdout);     \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+                                                                       \
+    pre##_ccminit(&ctx, &key, (octet *)v[1].buf, v[1].len,             \
+                 v[2].len, v[4].len, v[5].len);                        \
+                                                                       \
+    i = *ip;                                                           \
+    hsz = v[2].len;                                                    \
+    if (i == -1) i = hsz;                                              \
+    if (i > hsz) continue;                                             \
+    p = (octet *)v[2].buf;                                             \
+    while (hsz) {                                                      \
+      if (i > hsz) i = hsz;                                            \
+      pre##_ccmaadhash(&ctx, p, i);                                    \
+      p += i; hsz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[4].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[4].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_ccmdecrypt(&ctx, p, i, &b)) {                          \
+       puts("!! ccmdecrypt reports failure");                          \
+       win = 0; goto fail_dec;                                         \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    win = pre##_ccmdecryptdone(&ctx, &b, (octet *)v[5].buf, v[5].len); \
+    if (win < 0) {                                                     \
+      puts("!! ccmdecryptdone reports failure");                       \
+      goto fail_dec;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[3].len || !win ||                                   \
+       memcmp(d.buf, v[3].buf, v[3].len) != 0) {                       \
+    fail_dec:                                                          \
+      printf("\nfail decrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tciphertext = ", stdout); type_hex.dump(&v[4], stdout);        \
+      fputs("\n\texp pt = ", stdout); type_hex.dump(&v[3], stdout);    \
+      fputs("\n\tcalc pt = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\ttag = ", stdout); type_hex.dump(&v[5], stdout);       \
+      printf("\n\tverify %s", win ? "ok" : "FAILED");                  \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  dstr_destroy(&d); dstr_destroy(&t);                                  \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static test_chunk aeaddefs[] = {                                       \
+  { name "-ccm", ccmverify,                                            \
+    { &type_hex, &type_hex, &type_hex, &type_hex,                      \
+      &type_hex, &type_hex, 0 } },                                     \
+  { 0, 0, { 0 } }                                                      \
+};                                                                     \
+                                                                       \
+int main(int argc, char *argv[])                                       \
+{                                                                      \
+  ego(argv[0]);                                                                \
+  test_run(argc, argv, aeaddefs, SRCDIR"/t/" fname);                   \
+  return (0);                                                          \
+}
+
+#else
+#  define CCM_TESTX(PRE, pre, name, fname)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/ccm.c b/symm/ccm.c
new file mode 100644 (file)
index 0000000..d65e049
--- /dev/null
@@ -0,0 +1,201 @@
+/* -*-c-*-
+ *
+ * CCM common code
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "ccm.h"
+#include "ccm-def.h"
+
+/*----- MAC header and counter formatting ---------------------------------*
+ *
+ * CCM's most endearing feature is its complex formatting of the MAC
+ * initialization vector and counter blocks.  This is only specified for
+ * 128-bit blocks, so I've made up formats for 64-, 192-, and 256-bit blocks.
+ * For completeness and ease of comparison, all of the encodings are defined
+ * here.  Encoding of the rest of the MAC input data is common.
+ *
+ * The notation is taken from the definition of CCM in NIST SP800-38C.
+ *
+ *   * [x]_w = encoding of x, as w bits
+ *   * P = plaintext/ciphertext
+ *   * p = length of P in octets
+ *   * Q = [p]_{8q} = encoding of p
+ *   * q = length of Q in octets
+ *   * N = nonce
+ *   * H = B_0 = MAC header block
+ *   * C_i = the i-th counter block
+ *   * t = length of tag in octets
+ *
+ * 128-bit blocks (SP800-38C, appendix A):
+ *
+ * Let F be an octet:
+ *
+ *     Bits            7       6       6:3             3:0
+ *     Meaning         0       AAD?    [t/2 - 1]_3     [q - 1]_3
+ *
+ * Then H = F || N || Q and C_i = 0^5 || [q - 1]_3 || N || [i]_{8q}.
+ *
+ * 64-bit blocks (new):
+ *
+ * Let F be an octet:
+ *
+ *     Bits            7       6       6:3             3:0
+ *     Meaning         0       AAD?    [t - 1]_3       [q - 1]_3
+ *
+ * Then H = F || N || Q and C_i = 0^5 || [q - 1]_3 || N || [i]_{8q}.
+ *
+ * (i.e., almost exactly the same, except that the tag no longer needs to be
+ * an even number of octets).
+ *
+ * n-bit blocks, for n > 128
+ *
+ * Let F be a 16-bit flags word:
+ *
+ *     Bits            15      15:8            7       7:0
+ *     Meaning         0       [t]_7           AAD?    [q]_7
+ *
+ * Then H = F || N || Q and C_i = 0^9 || [q - 1]_7 || N || [i]_{8q}.
+ */
+
+/* --- @ccm_paramsok@ --- *
+ *
+ * Arguments:  @const ccm_params *p@ = pointer to parameters
+ *
+ * Returns:    True (nonzero) if the parameters are OK; false (zero) if
+ *             there's a problem.
+ *
+ * Use:                Verify that the CCM parameters are acceptable.
+ */
+
+int ccm_check(const ccm_params *p)
+{
+  unsigned fsz = p->bsz <= 16 ? 1 : 2, q = p->bsz - p->nsz - fsz, i;
+  size_t msz;
+
+  /* Check that the block size hasn't been bungled. */
+  if (p->bsz < 16 && p->bsz != 8) return (0);
+
+  /* The length-of-the-length must be representable, and its encoding must
+   * not be zero, since this is `reserved'.  The small-block encoding stores
+   * %$q - 1$%, so we must have %$q \ge 2$%; the large-block encoding stores
+   * %$q$% directly, so only %$q = 0$% is forbidden.
+   */
+  if (p->nsz > p->bsz - fsz - (p->bsz <= 16 ? 2 : 1)) return (0);
+  if (q > (p->bsz <= 16 ? 8 : 127)) return (0);
+
+  /* Verify that the message length will fit in the space allotted. */
+  for (i = 1, msz = p->msz >> 8; msz; i++, msz >>= 8);
+  if (i > q) return (0);
+
+  /* The tag can't be larger than the block size.  Also, it must be
+   * representable, and its encoding must not be zero, because otherwise it'd
+   * be possible for a MAC header block to look like a counter block.  The
+   * tag encoding is fiddly: for 64-bit blocks, we store %$t - 1$%, so we
+   * must have %$t \ge 2$%; for 128-bit blocks, we store %$t/2 - 2$%, so
+   * we must have %$t \ge 4$% with %$t$% even; otherwise, we store %$t$%
+   * directly, so the only requirement is that %$t \ge 1$%.
+   */
+  if (p->tsz > p->bsz) return (0);
+  if (p->tsz < (p->bsz == 8 ? 2 : p->bsz == 16 ? 4 : 1)) return (0);
+  if (p->bsz == 16 && p->tsz%2 != 0) return (0);
+
+  /* All looks good. */
+  return (1);
+}
+
+/* --- @ccm_fmthdr@ --- *
+ *
+ * Arguments:  @const ccm_params *p@ = pointer to parameters
+ *             @octet *b@ = block-size buffer to write header
+ *             @const void *n@ = pointer to nonce
+ *
+ * Returns:    ---
+ *
+ * Use:                Format a MAC header block.
+ */
+
+void ccm_fmthdr(const ccm_params *p, octet *b, const void *n)
+{
+  size_t fsz = p->bsz <= 16 ? 1 : 2, q = p->bsz - p->nsz - fsz;
+  unsigned f0 = 0, f1 = 0;
+  size_t i, t;
+
+  /* Encode whether the AAD is empty. */
+  if (!p->hsz) /* do nothing */;
+  else if (p->bsz <= 16) f0 |= 0x40;
+  else f1 |= 0x80;
+
+  /* Encode the tag size. */
+  switch (p->bsz) {
+    case  8: f0 |= (p->tsz - 1) << 3; break;
+    case 16: f0 |= (p->tsz - 2) << 2; break;
+    default: f0 |=  p->tsz;          break;
+  }
+
+  /* Encode the length-of-the-length.  (This is the most bletcherous part of
+   * CCM.)
+   */
+  if (p->bsz <= 16) f0 |= q - 1;
+  else f1 |= q;
+
+  /* Insert the flags and nonce. */
+  b[0] = f0; memcpy(b + fsz, n, p->nsz);
+  if (p->bsz > 16) b[1] = f1;
+
+  /* Write the message length. */
+  for (i = 0, t = p->msz; i < q; i++, t >>= 8) b[p->bsz - i - 1] = U8(t);
+}
+
+/* --- @ccm_fmtctr@ --- *
+ *
+ * Arguments:  @const ccm_params *p@ = pointer to parameters
+ *             @octet *b@ = block-size buffer to write header
+ *             @const void *n@ = pointer to nonce
+ *
+ * Returns:    ---
+ *
+ * Use:                Format an initial counter block.
+ */
+
+void ccm_fmtctr(const ccm_params *p, octet *b, const void *n)
+{
+  size_t fsz = p->bsz <= 16 ? 1 : 2, q = p->bsz - p->nsz - fsz;
+  unsigned f0 = 0, f1 = 0;
+
+  /* Encode the message length length.  (Did I complain about this?) */
+  if (p->bsz <= 16) f0 |= q - 1;
+  else f1 |= q;
+
+  /* Insert the flags and nonce. */
+  b[0] = f0; memcpy(b + fsz, n, p->nsz);
+  if (p->bsz > 16) b[1] = f1;
+
+  /* Zero out the initial counter. */
+  memset(b + fsz + p->nsz, 0, q);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/symm/ccm.h b/symm/ccm.h
new file mode 100644 (file)
index 0000000..ebbcc42
--- /dev/null
@@ -0,0 +1,327 @@
+/* -*-c-*-
+ *
+ * The CCM authenticated-encryption mode
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Notes on CCM ------------------------------------------------------*
+ *
+ * The name is short for `Counter with CBC-MAC'.  CCM was designed in 2002 by
+ * Russ Housley, Doug Whiting, and Niels Ferguson to be a patent-free
+ * alternative to Rogaway's OCB, and is specified by NIST in SP800-38C.  It's
+ * a classic two-pass authenticated encryption scheme, so it needs two
+ * blockcipher applications per message block.
+ *
+ * Unfortunately, CCM is rather annoying in actual use.  The internals
+ * involve quite a lot of fiddly framing, which I've had to generalize for
+ * block sizes other than 128 bits, but that's not exposed beyond the API.
+ * (This does mean that it's rather unlikely that Catacomb's CCM will
+ * interoperate with anyone else's when using a blockcipher with a block size
+ * other than 128 bits.)
+ *
+ * More problematically:
+ *
+ *   * The mode requires that callers precommit to the header, message, and
+ *     tag sizes before commencing processing.  If you don't know these in
+ *     advance then you can't use CCM.
+ *
+ *   * The mode requires that callers present all of the header data before
+ *     encrypting the message.
+ *
+ *   * The header data processing is dependent on the nonce (and the message
+ *     and tag lengths), so it's not possible to preprocess a constant prefix
+ *     of the header.
+ *
+ *   * There's an uncomfortable tradeoff between nonce length and message
+ *     length because the counter input holds both in separate fields, with a
+ *     variably-positioned split between them.
+ *
+ * The implementation is very picky and will abort if you get things wrong.
+ */
+
+#ifndef CATACOMB_CCM_H
+#define CATACOMB_CCM_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+/*----- Common machinery -------------------------------------------------*/
+
+typedef struct ccm_params {
+  unsigned long hsz, msz;              /* AAD and message lengths */
+  unsigned bsz, nsz, tsz;              /* Block, nonce and tag length */
+} ccm_params;
+
+enum { CCMST_AAD, CCMST_MSG };
+
+/* Minimum and maximum nonce lengths.
+ *
+ * Let the block size be %$N$% bytes, and let %$q$% be the length-of-the-
+ * length of the messaage.  The nonce length is not encoded directly; rather,
+ * it's what's left after the flags bytes and message length fields have been
+ * allocated.
+ *
+ * The maximum is always %$N - 3$%.  If %$N \le 16$%, then there is one byte
+ * used for flags, and at least two bytes for the message length/counter:
+ * (since %$q$% is encoded in a 3-bit field as %$q - 1$%, %$q = 0$% cannot be
+ * encoded and the encoding zero, for %$q = 1$%, is reserved.  If %$N > 16$
+ * then there are two flags bytes, but %$q$% is encoded directly, so only
+ * %$q = 0$% is reserved.
+ *
+ * The minimum is more complicated.  If %$N \le 16$% then we must have %$q
+ * \le 8$%; with one flags byte, this leaves at least %$\max\{ 0, N - 9 \}$%
+ * bytes for the nonce.  When %$N = 8$% this is zero, but when %$N = 16$%
+ * this is 7.  When %$N > 16$%, there are two flags bits, but %$q \le 127$%
+ * (since %$q$%) is encoded directly: thus the nonce may be empty if
+ * %$16 < N \le 129$%, and otherwise must be at least %$N - 129$% bytes.
+ */
+#define CCM_NSZMIN(PRE) (PRE##_BLKSZ == 16 ? 7 :                       \
+                        PRE##_BLKSZ <= 129 ? 0 :                       \
+                        PRE##_BLKSZ - 129)
+#define CCM_NSZMAX(PRE) (PRE##_BLKSZ - 3)
+
+/* Minimum and maximum tag lengths.
+ *
+ * This is even more exasperating.  Again, let the block size be %$N$% bytes;
+ * let %$t$% be the tag length.
+ *
+ * When %$N = 16$%, the tag length is encoded as %$t/2 - 1$% in a three-bit
+ * field, and the encoding zero is reserved.  (The security of the scheme
+ * depends on this reservation to disambiguate MAC header blocks from
+ * counters; I'd have used the remaining flag bit.)  Anyway, this leaves
+ * %$1 \le t/2 - 1 \le 7$%, so we must have %$4 \le t \le 16$% with %$t$%
+ * even.
+ *
+ * When %$N = 8$%, the tag length is encoded in three bits as %$t - 1$%;
+ * again, the zero encoding is reserved.  This leaves %$2 \le t \le 8$%.
+ *
+ * Finally, when %$N \ge 16$%, the tag length is encoded directly in a
+ * seven-bit field.  The zero encoding is still reserved, so we have
+ * %$1 \le t \le \min \{ N, 127 \}$%.
+ */
+#define CCM_TSZMIN(PRE) (PRE##_BLKSZ == 8 ? 2 :                                \
+                        PRE##_BLKSZ == 16 ? 4 :                        \
+                        1)
+#define CCM_TSZMAX(PRE) (PRE##_BLKSZ <= 127 ? PRE##_BLKSZ : 127)
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @CCM_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates declarations for CCM authenticated-encryption mode.
+ */
+
+#define CCM_DECL(PRE, pre)                                             \
+                                                                       \
+typedef struct pre##_ccmctx {                                          \
+  /* The buffer is split into two portions during encryption/          \
+   * decryption.  The first N octets hold a chunk of plaintext, which  \
+   * will be fed into the CBC-MAC calculation; the remaining BLKSZ - N \
+   * octets hold E_K(C), which is the XOR mask to apply to the         \
+   * plaintext or ciphertext.                                          \
+   */                                                                  \
+  pre##_ctx k;                         /* Underlying key */            \
+  ccm_params p;                                /* CCM parameters */            \
+  unsigned long i;                     /* Current position in bytes */ \
+  unsigned st;                         /* Current state */             \
+  uint32 c[PRE##_BLKSZ/4];             /* Current counter value */     \
+  uint32 a[PRE##_BLKSZ/4];             /* CBC-MAC accumulator */       \
+  uint32 s0[PRE##_BLKSZ/4];            /* Mask for MAC tag */          \
+  octet b[PRE##_BLKSZ];                        /* AAD or msg/mask buffer */    \
+  unsigned off;                                /* Crossover point in buffer */ \
+} pre##_ccmctx;                                                                \
+                                                                       \
+extern const octet pre##_ccmnoncesz[], pre##_ccmtagsz[];               \
+                                                                       \
+/* --- @pre_ccminit@ --- *                                             \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *aad@ = pointer to CCM context              \
+ *             @const pre_ctx *k@ = pointer to key material            \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of the nonce                        \
+ *             @size_t hsz@ = size of the AAD                          \
+ *             @size_t msz@ = size of the message/ciphertext           \
+ *             @size_t tsz@ = size of the tag to produce               \
+ *                                                                     \
+ * Returns:    Zero on success; nonzero if the parameters are invalid. \
+ *                                                                     \
+ * Use:                Initialize an CCM operation context with a given key.   \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+extern int pre##_ccminit(pre##_ccmctx */*ctx*/,                                \
+                        const pre##_ctx */*k*/,                        \
+                        const void */*n*/, size_t /*nsz*/,             \
+                        size_t /*hsz*/, size_t /*msz*/,                \
+                        size_t /*tsz*/);                               \
+                                                                       \
+/* --- @pre_ccmreinit@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to CCM context              \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *             @size_t hsz@ = size of the AAD                          \
+ *             @size_t msz@ = size of the message/ciphertext           \
+ *             @size_t tsz@ = size of the tag to produce               \
+ *                                                                     \
+ * Returns:    Zero on success; nonzero if the parameters are invalid. \
+ *                                                                     \
+ * Use:                Reinitialize an CCM operation context, changing the     \
+ *             nonce and/or other parameters.                          \
+ */                                                                    \
+                                                                       \
+extern int pre##_ccmreinit(pre##_ccmctx */*ctx*/,                      \
+                          const void */*n*/, size_t /*nsz*/,           \
+                          size_t /*hsz*/, size_t /*msz*/,              \
+                          size_t /*tsz*/);                             \
+                                                                       \
+/* --- @pre_ccmaadhash@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to AAD context              \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.  This must be done before   \
+ *             any of the message/ciphertext is processed because CCM  \
+ *             is really annoying like that.                           \
+ */                                                                    \
+                                                                       \
+extern void pre##_ccmaadhash(pre##_ccmctx */*ctx*/,                    \
+                            const void */*p*/, size_t /*sz*/);         \
+                                                                       \
+/* --- @pre_ccmencrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to CCM operation context    \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For CCM, we always write a ciphertext chunk the same    \
+ *             size as the plaintext.  The messing about with @buf@    \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+extern int pre##_ccmencrypt(pre##_ccmctx */*ctx*/,                     \
+                           const void */*src*/, size_t /*sz*/,         \
+                           buf */*dst*/);                              \
+                                                                       \
+/* --- @pre_ccmdecrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to CCM operation context    \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For CCM, we always write a plaintext chunk the same     \
+ *             size as the ciphertext.  The messing about with @buf@   \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+extern int pre##_ccmdecrypt(pre##_ccmctx */*ctx*/,                     \
+                           const void */*src*/, size_t /*sz*/,         \
+                           buf */*dst*/);                              \
+                                                                       \
+/* --- @pre_ccmencryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to an CCM context           \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an CCM encryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  CCM doesn't buffer ciphertext, but \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+extern int pre##_ccmencryptdone(pre##_ccmctx */*ctx*/, buf */*dst*/,   \
+                               void */*tag*/, size_t /*tsz*/);         \
+                                                                       \
+/* --- @pre_ccmdecryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_ccmctx *ctx@ = pointer to an CCM context           \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an CCM decryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  CCM doesn't buffer plaintext, but  \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+extern int pre##_ccmdecryptdone(pre##_ccmctx */*ctx*/, buf */*dst*/,   \
+                               const void */*tag*/, size_t /*tsz*/);   \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+extern const gcaead pre##_ccm;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index 78aa6d9..303bc9f 100644 (file)
 #  include "paranoia.h"
 #endif
 
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
 /*----- Macros ------------------------------------------------------------*/
 
 /* --- @CFB_DEF@ --- *
@@ -90,8 +94,9 @@ void pre##_cfbgetiv(const pre##_cfbctx *ctx, void *iv)                        \
   octet *p = iv;                                                       \
   unsigned off = ctx->off;                                             \
   unsigned rest = PRE##_BLKSZ - off;                                   \
-  memcpy(p, ctx->iv + off, rest);                                      \
-  memcpy(p + rest, ctx->iv, off);                                      \
+                                                                       \
+  memcpy(p, ctx->b + off, rest);                                       \
+  memcpy(p + rest, ctx->b, off);                                       \
 }                                                                      \
                                                                        \
 /* --- @pre_cfbsetiv@ --- *                                            \
@@ -105,10 +110,7 @@ void pre##_cfbgetiv(const pre##_cfbctx *ctx, void *iv)                     \
  */                                                                    \
                                                                        \
 void pre##_cfbsetiv(pre##_cfbctx *ctx, const void *iv)                 \
-{                                                                      \
-  memcpy(ctx->iv, iv, PRE##_BLKSZ);                                    \
-  ctx->off = PRE##_BLKSZ;                                              \
-}                                                                      \
+  { memcpy(ctx->b, iv, PRE##_BLKSZ); ctx->off = 0; }                   \
                                                                        \
 /* --- @pre_cfbbdry@ --- *                                             \
  *                                                                     \
@@ -122,12 +124,13 @@ void pre##_cfbsetiv(pre##_cfbctx *ctx, const void *iv)                    \
                                                                        \
 void pre##_cfbbdry(pre##_cfbctx *ctx)                                  \
 {                                                                      \
-  uint32 niv[PRE##_BLKSZ / 4];                                         \
-  BLKC_LOAD(PRE, niv, ctx->iv);                                                \
-  pre##_eblk(&ctx->ctx, niv, niv);                                     \
-  BLKC_STORE(PRE, ctx->iv, niv);                                       \
-  ctx->off = PRE##_BLKSZ;                                              \
-  BURN(niv);                                                           \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+                                                                       \
+  BLKC_LOAD(PRE, t, ctx->b);                                           \
+  pre##_eblk(&ctx->ctx, t, t);                                         \
+  BLKC_STORE(PRE, ctx->b, t);                                          \
+  ctx->off = 0;                                                                \
+  BURN(t);                                                             \
 }                                                                      \
                                                                        \
 /* --- @pre_cfbsetkey@ --- *                                           \
@@ -141,10 +144,7 @@ void pre##_cfbbdry(pre##_cfbctx *ctx)                                      \
  */                                                                    \
                                                                        \
 void pre##_cfbsetkey(pre##_cfbctx *ctx, const pre##_ctx *k)            \
-{                                                                      \
-  ctx->ctx = *k;                                                       \
-  ctx->off = PRE##_BLKSZ;                                              \
-}                                                                      \
+  { ctx->ctx = *k; ctx->off = 0; }                                     \
                                                                        \
 /* --- @pre_cfbinit@ --- *                                             \
  *                                                                     \
@@ -163,10 +163,11 @@ void pre##_cfbsetkey(pre##_cfbctx *ctx, const pre##_ctx *k)               \
  */                                                                    \
                                                                        \
 void pre##_cfbinit(pre##_cfbctx *ctx,                                  \
-                    const void *key, size_t sz,                        \
-                    const void *iv)                                    \
+                  const void *key, size_t sz,                          \
+                  const void *iv)                                      \
 {                                                                      \
   static const octet zero[PRE##_BLKSZ] = { 0 };                                \
+                                                                       \
   pre##_init(&ctx->ctx, key, sz);                                      \
   pre##_cfbsetiv(ctx, iv ? iv : zero);                                 \
 }                                                                      \
@@ -185,75 +186,75 @@ void pre##_cfbinit(pre##_cfbctx *ctx,                                     \
  *             sensitive to block boundaries.                          \
  */                                                                    \
                                                                        \
+static const rsvr_policy pre##_cfbpolicy = { 0, PRE##_BLKSZ, PRE##_BLKSZ }; \
+                                                                       \
 void pre##_cfbencrypt(pre##_cfbctx *ctx,                               \
-                       const void *src, void *dest,                    \
-                       size_t sz)                                      \
+                     const void *src, void *dest,                      \
+                     size_t sz)                                        \
 {                                                                      \
+  rsvr_plan plan;                                                      \
   const octet *s = src;                                                        \
-  octet *d = dest;                                                     \
-  unsigned off = ctx->off;                                             \
-                                                                       \
-  /* --- Empty blocks are trivial --- */                               \
-                                                                       \
-  if (!sz)                                                             \
-    return;                                                            \
-                                                                       \
-  /* --- If I can deal with the block from my buffer, do that --- */   \
-                                                                       \
-  if (sz < PRE##_BLKSZ - off)                                          \
-    goto small;                                                                \
-                                                                       \
-  /* --- Finish off what's left in my buffer --- */                    \
-                                                                       \
-  while (off < PRE##_BLKSZ) {                                          \
-    register octet x = *s++;                                           \
-    ctx->iv[off] ^= x;                                                 \
-    if (d) *d++ = ctx->iv[off];                                                \
-    off++;                                                             \
-    sz--;                                                              \
+  octet *d = dest, *p;                                                 \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  octet y;                                                             \
+                                                                       \
+  /* Construct a plan and prepare to follow through. */                        \
+  rsvr_mkplan(&plan, &pre##_cfbpolicy, ctx->off, sz);                  \
+  BLKC_LOAD(PRE, t, ctx->b);                                           \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the chunk is small        \
+   * enough, then this will be the only portion.  If the buffer is     \
+   * currently empty, then we must prepare it.                         \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      pre##_eblk(&ctx->ctx, t, t);                                     \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
+    }                                                                  \
+    p = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    if (s) while (plan.head--) { y = *s++ ^ *p; *p++ = y; if (d) *d++ = y; } \
+    else if (d) { memcpy(d, p, plan.head); d += plan.head; }           \
+    BLKC_LOAD(PRE, t, ctx->b);                                         \
   }                                                                    \
                                                                        \
-  /* --- Main encryption loop --- */                                   \
-                                                                       \
-  {                                                                    \
-    uint32 iv[PRE##_BLKSZ / 4];                                                \
-    BLKC_LOAD(PRE, iv, ctx->iv);                                       \
-                                                                       \
-    for (;;) {                                                         \
-      pre##_eblk(&ctx->ctx, iv, iv);                                   \
-      if (sz < PRE##_BLKSZ)                                            \
-       break;                                                          \
-      if (s) {                                                         \
-       BLKC_XLOAD(PRE, iv, s);                                         \
-       s += PRE##_BLKSZ;                                               \
-      }                                                                        \
-      if (d) {                                                         \
-       BLKC_STORE(PRE, d, iv);                                         \
-       d += PRE##_BLKSZ;                                               \
-      }                                                                        \
-      sz -= PRE##_BLKSZ;                                               \
+  /* If the buffer is all used, then reset it ready for next time. */  \
+  ctx->off -= plan.from_rsvr;                                          \
+                                                                       \
+  /* Handle multiple whole blocks. */                                  \
+  if (!d) {                                                            \
+    if (!s) while (plan.from_input) {                                  \
+      pre##_eblk(&ctx->ctx, t, t);                                     \
+      plan.from_input -= PRE##_BLKSZ;                                  \
+    } else while (plan.from_input) {                                   \
+      pre##_eblk(&ctx->ctx, t, t);                                     \
+      BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ;                         \
+      plan.from_input -= PRE##_BLKSZ;                                  \
+    }                                                                  \
+  } else {                                                             \
+    if (!s) while (plan.from_input) {                                  \
+      pre##_eblk(&ctx->ctx, t, t);                                     \
+      BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ;                         \
+      plan.from_input -= PRE##_BLKSZ;                                  \
+    } else while (plan.from_input) {                                   \
+      pre##_eblk(&ctx->ctx, t, t);                                     \
+      BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ;                         \
+      BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ;                         \
+      plan.from_input -= PRE##_BLKSZ;                                  \
     }                                                                  \
-    off = 0;                                                           \
-    BLKC_STORE(PRE, ctx->iv, iv);                                      \
   }                                                                    \
                                                                        \
-  /* --- Tidying up the tail end --- */                                        \
-                                                                       \
-  if (sz) {                                                            \
-  small:                                                               \
-    do {                                                               \
-      register octet x = *s++;                                         \
-      ctx->iv[off] ^= x;                                               \
-      if (d) *d++ = ctx->iv[off];                                      \
-      off++;                                                           \
-      sz--;                                                            \
-    } while (sz);                                                      \
+  /* Final portion.  Note that the buffer must be empty if there is a  \
+   * tail, since otherwise the input data would have been part of the  \
+   * head portion instad. */                                           \
+  if (!plan.tail)                                                      \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+  else {                                                               \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    p = ctx->b; ctx->off += plan.tail;                                 \
+    if (s) while (plan.tail--) { y = *s++ ^ *p; *p++ = y; if (d) *d++ = y; } \
+    else if (d) { memcpy(d, p, plan.tail); d += plan.tail; }           \
   }                                                                    \
-                                                                       \
-  /* --- Done --- */                                                   \
-                                                                       \
-  ctx->off = off;                                                      \
-  return;                                                              \
 }                                                                      \
                                                                        \
 /* --- @pre_cfbdecrypt@ --- *                                          \
@@ -271,70 +272,58 @@ void pre##_cfbencrypt(pre##_cfbctx *ctx,                          \
  */                                                                    \
                                                                        \
 void pre##_cfbdecrypt(pre##_cfbctx *ctx,                               \
-                       const void *src, void *dest,                    \
-                       size_t sz)                                      \
+                     const void *src, void *dest,                      \
+                     size_t sz)                                        \
 {                                                                      \
+  rsvr_plan plan;                                                      \
   const octet *s = src;                                                        \
-  octet *d = dest;                                                     \
-  unsigned off = ctx->off;                                             \
-                                                                       \
-  /* --- Empty blocks are trivial --- */                               \
-                                                                       \
-  if (!sz)                                                             \
-    return;                                                            \
-                                                                       \
-  /* --- If I can deal with the block from my buffer, do that --- */   \
-                                                                       \
-  if (sz < PRE##_BLKSZ - off)                                          \
-    goto small;                                                                \
-                                                                       \
-  /* --- Finish off what's left in my buffer --- */                    \
-                                                                       \
-  while (off < PRE##_BLKSZ) {                                          \
-    register octet x = *s++;                                           \
-    *d++ = ctx->iv[off] ^ x;                                           \
-    ctx->iv[off++] = x;                                                        \
-    sz--;                                                              \
-  }                                                                    \
-                                                                       \
-  /* --- Main encryption loop --- */                                   \
-                                                                       \
-  {                                                                    \
-    uint32 iv[PRE##_BLKSZ / 4];                                                \
-    BLKC_LOAD(PRE, iv, ctx->iv);                                       \
-                                                                       \
-    for (;;) {                                                         \
-      uint32 x[PRE##_BLKSZ / 4];                                       \
-      pre##_eblk(&ctx->ctx, iv, iv);                                   \
-      if (sz < PRE##_BLKSZ)                                            \
-       break;                                                          \
-      BLKC_LOAD(PRE, x, s);                                            \
-      BLKC_XSTORE(PRE, d, iv, x);                                      \
-      BLKC_MOVE(PRE, iv, x);                                           \
-      s += PRE##_BLKSZ;                                                        \
-      d += PRE##_BLKSZ;                                                        \
-      sz -= PRE##_BLKSZ;                                               \
+  octet *d = dest, *p;                                                 \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ/4];                           \
+  octet y;                                                             \
+                                                                       \
+  /* Construct a plan and prepare to follow through. */                        \
+  rsvr_mkplan(&plan, &pre##_cfbpolicy, ctx->off, sz);                  \
+  BLKC_LOAD(PRE, t, ctx->b);                                           \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the chunk is small        \
+   * enough, then this will be the only portion.  If the buffer is     \
+   * currently empty, then we must prepare it.                         \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      pre##_eblk(&ctx->ctx, t, t);                                     \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
     }                                                                  \
-    off = 0;                                                           \
-    BLKC_STORE(PRE, ctx->iv, iv);                                      \
+    p = ctx->b + ctx->off;                                             \
+    ctx->off += plan.head;                                             \
+    while (plan.head--) { y = *s++; *d++ = y ^ *p; *p++ = y; }         \
+    BLKC_LOAD(PRE, t, ctx->b);                                         \
   }                                                                    \
                                                                        \
-  /* --- Tidying up the tail end --- */                                        \
+  /* If the buffer is all used, then reset it ready for next time. */  \
+  ctx->off -= plan.from_rsvr;                                          \
                                                                        \
-  if (sz) {                                                            \
-  small:                                                               \
-    do {                                                               \
-      register octet x = *s++;                                         \
-      *d++ = ctx->iv[off] ^ x;                                         \
-      ctx->iv[off++] = x;                                              \
-      sz--;                                                            \
-    } while (sz);                                                      \
+  /* Handle multiple whole blocks. */                                  \
+  while (plan.from_input) {                                            \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_LOAD(PRE, u, s); s += PRE##_BLKSZ;                            \
+    BLKC_XSTORE(PRE, d, t, u); d += PRE##_BLKSZ;                       \
+    BLKC_MOVE(PRE, t, u);                                              \
+    plan.from_input -= PRE##_BLKSZ;                                    \
   }                                                                    \
                                                                        \
-  /* --- Done --- */                                                   \
-                                                                       \
-  ctx->off = off;                                                      \
-  return;                                                              \
+  /* Final portion.  Note that the buffer must be empty if there is a  \
+   * tail, since otherwise the input data would have been part of the  \
+   * head portion instad. */                                           \
+  if (!plan.tail)                                                      \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+  else {                                                               \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    p = ctx->b;                                                                \
+    ctx->off += plan.tail;                                             \
+    while (plan.tail--) { y = *s++; *d++ = y ^ *p; *p++ = y; }         \
+  }                                                                    \
 }                                                                      \
                                                                        \
 /* --- Generic cipher interface --- */                                 \
@@ -355,35 +344,19 @@ static gcipher *ginit(const void *k, size_t sz)                           \
 }                                                                      \
                                                                        \
 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_cfbencrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_cfbencrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdecrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_cfbdecrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_cfbdecrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdestroy(gcipher *c)                                       \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  BURN(*g);                                                            \
-  S_DESTROY(g);                                                                \
-}                                                                      \
+  { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }                     \
                                                                        \
 static void gsetiv(gcipher *c, const void *iv)                         \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_cfbsetiv(&g->k, iv);                                           \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_cfbsetiv(&g->k, iv); }                  \
                                                                        \
 static void gbdry(gcipher *c)                                          \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_cfbbdry(&g->k);                                                        \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_cfbbdry(&g->k); }                       \
                                                                        \
 static const gcipher_ops gops = {                                      \
   &pre##_cfb,                                                          \
@@ -403,9 +376,7 @@ CFB_TESTX(PRE, pre, name, fname)
 
 #ifdef TEST_RIG
 
-#include <stdio.h>
-
-#include "daftstory.h"
+#include "modes-test.h"
 
 /* --- @CFB_TEST@ --- *
  *
@@ -416,85 +387,27 @@ CFB_TESTX(PRE, pre, name, fname)
 
 #define CFB_TESTX(PRE, pre, name, fname)                               \
                                                                        \
-/* --- Initial plaintext for the test --- */                           \
-                                                                       \
-static const octet text[] = TEXT;                                      \
-                                                                       \
-/* --- Key and IV to use --- */                                                \
+static pre##_ctx key;                                                  \
+static pre##_cfbctx ctx;                                               \
                                                                        \
-static const octet key[] = KEY;                                                \
-static const octet iv[] = IV;                                          \
+static void pre##_cfb_test_setup(const octet *k, size_t ksz)           \
+  { pre##_init(&key, k, ksz); pre##_cfbsetkey(&ctx, &key); }           \
                                                                        \
-/* --- Buffers for encryption and decryption output --- */             \
+static void pre##_cfb_test_reset(const octet *iv)                      \
+  { pre##_cfbsetiv(&ctx, iv); }                                                \
                                                                        \
-static octet ct[sizeof(text)];                                         \
-static octet pt[sizeof(text)];                                         \
+static void pre##_cfb_test_enc(const octet *s, octet *d, size_t sz)    \
+  { pre##_cfbencrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-static void hexdump(const octet *p, size_t sz, size_t off)             \
-{                                                                      \
-  const octet *q = p + sz;                                             \
-  for (sz = 0; p < q; p++, sz++) {                                     \
-    printf("%02x", *p);                                                        \
-    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
-      putchar(':');                                                    \
-  }                                                                    \
-}                                                                      \
+static void pre##_cfb_test_dec(const octet *s, octet *d, size_t sz)    \
+  { pre##_cfbdecrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-int main(void)                                                         \
+int main(int argc, char *argv[])                                       \
 {                                                                      \
-  size_t sz = 0, rest;                                                 \
-  pre##_cfbctx ctx;                                                    \
-  int status = 0;                                                      \
-  int done = 0;                                                                \
-  pre##_ctx k;                                                         \
-                                                                       \
-  size_t keysz = PRE##_KEYSZ ?                                         \
-    PRE##_KEYSZ : strlen((const char *)key);                           \
-                                                                       \
-  fputs(name "-cfb: ", stdout);                                                \
-                                                                       \
-  pre##_init(&k, key, keysz);                                          \
-  pre##_cfbsetkey(&ctx, &k);                                           \
-                                                                       \
-  while (sz <= sizeof(text)) {                                         \
-    rest = sizeof(text) - sz;                                          \
-    memcpy(ct, text, sizeof(text));                                    \
-    pre##_cfbsetiv(&ctx, iv);                                          \
-    pre##_cfbencrypt(&ctx, ct, ct, sz);                                        \
-    pre##_cfbencrypt(&ctx, ct + sz, ct + sz, rest);                    \
-    memcpy(pt, ct, sizeof(text));                                      \
-    pre##_cfbsetiv(&ctx, iv);                                          \
-    pre##_cfbdecrypt(&ctx, pt, pt, rest);                              \
-    pre##_cfbdecrypt(&ctx, pt + rest, pt + rest, sz);                  \
-    if (memcmp(pt, text, sizeof(text)) == 0) {                         \
-      done++;                                                          \
-      if (sizeof(text) < 40 || done % 8 == 0)                          \
-       fputc('.', stdout);                                             \
-      if (done % 480 == 0)                                             \
-       fputs("\n\t", stdout);                                          \
-      fflush(stdout);                                                  \
-    } else {                                                           \
-      printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
-      status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
-       printf(", "); hexdump(text + sz, rest, sz);                     \
-       fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
-       printf(", "); hexdump(ct + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
-       printf(", "); hexdump(pt + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      fputc('\n', stdout);                                             \
-    }                                                                  \
-    if (sz < 63)                                                       \
-      sz++;                                                            \
-    else                                                               \
-      sz += 9;                                                         \
-  }                                                                    \
-                                                                       \
-  fputs(status ? " failed\n" : " ok\n", stdout);                       \
-  return (status);                                                     \
+  return test_encmode(fname "-cfb", PRE##_KEYSZ, PRE##_BLKSZ, 1, 0,    \
+                     pre##_cfb_test_setup, pre##_cfb_test_reset,       \
+                     pre##_cfb_test_enc, pre##_cfb_test_dec,           \
+                     argc, argv);                                      \
 }
 
 #else
index c357115..ddaa5fd 100644 (file)
@@ -58,7 +58,7 @@
 typedef struct pre##_cfbctx {                                          \
   pre##_ctx ctx;                       /* Underlying cipher context */ \
   unsigned off;                                /* Offset into @iv@ buffer */   \
-  octet iv[PRE##_BLKSZ];               /* Previous ciphertext or IV */ \
+  octet b[PRE##_BLKSZ];                        /* Previous ciphertext or IV */ \
 } pre##_cfbctx;                                                                \
                                                                        \
 /* --- @pre_cfbgetiv@ --- *                                            \
index af53cfd..a900db7 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
-///--------------------------------------------------------------------------
-/// Main.code.
-
        .arch   armv7-a
        .fpu    neon
+
        .text
 
+///--------------------------------------------------------------------------
+/// Main.code.
+
 FUNC(chacha_core_arm_neon)
 
        // Arguments are in registers.
index a423e9e..61ac51a 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
-///--------------------------------------------------------------------------
-/// Main.code.
-
        .arch   armv8-a
+
        .text
 
+///--------------------------------------------------------------------------
+/// Main.code.
+
 FUNC(chacha_core_arm64)
 
        // Arguments are in registers.
diff --git a/symm/chacha-poly1305.c b/symm/chacha-poly1305.c
new file mode 100644 (file)
index 0000000..657987e
--- /dev/null
@@ -0,0 +1,86 @@
+/* -*-c-*-
+ *
+ * AEAD schemes based on ChaCha and Poly1305
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "chacha.h"
+#include "latinpoly-def.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+LATINPOLY_DEF(chacha20, chacha, "chacha20")
+LATINPOLY_DEF(chacha12, chacha, "chacha12")
+LATINPOLY_DEF(chacha8, chacha, "chacha8")
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+#include "latinpoly-test.h"
+
+static int check_chacha20_poly1305(dstr *v)
+  { return latinpoly_test(&chacha20_poly1305, v); }
+static int check_chacha12_poly1305(dstr *v)
+  { return latinpoly_test(&chacha12_poly1305, v); }
+static int check_chacha8_poly1305(dstr *v)
+  { return latinpoly_test(&chacha8_poly1305, v); }
+static int check_chacha20_naclbox(dstr *v)
+  { return latinpoly_test(&chacha20_naclbox, v); }
+static int check_chacha12_naclbox(dstr *v)
+  { return latinpoly_test(&chacha12_naclbox, v); }
+static int check_chacha8_naclbox(dstr *v)
+  { return latinpoly_test(&chacha8_naclbox, v); }
+
+static const test_chunk tests[] = {
+  { "chacha20-poly1305", check_chacha20_poly1305,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "chacha12-poly1305", check_chacha12_poly1305,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "chacha8-poly1305", check_chacha8_poly1305,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "chacha20-naclbox", check_chacha20_naclbox,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "chacha12-naclbox", check_chacha12_naclbox,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "chacha8-naclbox", check_chacha8_naclbox,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { 0, 0, { 0 } }
+#undef TEST
+};
+
+int main(int argc, char *argv[])
+{
+  ego(argv[0]);
+  test_run(argc, argv, tests, SRCDIR"/t/chacha");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
index 2dab283..3fb623a 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
+       .text
+
 ///--------------------------------------------------------------------------
 /// Main code.
 
-       .arch pentium4
-       .text
+FUNC(chacha_core_x86ish_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       // drop through...
+ENDFUNC
+
+       .arch   pentium4
 
 FUNC(chacha_core_x86ish_sse2)
 
@@ -61,7 +69,7 @@ FUNC(chacha_core_x86ish_sse2)
 #  define SAVE3 [esp]
 
        pushreg ebp
-       setfp   ebp
+       setfp
        sub     esp, 16
        mov     IN, [ebp + 12]
        mov     OUT, [ebp + 16]
@@ -156,9 +164,9 @@ FUNC(chacha_core_x86ish_sse2)
 
        // c += d; b ^= c; b <<<=  7
        paddd   xmm2, xmm3
-        pshufd xmm3, xmm3, SHUF(2, 1, 0, 3)
+        pshufd xmm3, xmm3, SHUF(3, 0, 1, 2)
        pxor    xmm1, xmm2
-        pshufd xmm2, xmm2, SHUF(1, 0, 3, 2)
+        pshufd xmm2, xmm2, SHUF(2, 3, 0, 1)
        movdqa  xmm4, xmm1
        pslld   xmm1, 7
        psrld   xmm4, 25
@@ -176,7 +184,7 @@ FUNC(chacha_core_x86ish_sse2)
        //
        // The shuffles have quite high latency, so they've mostly been
        // pushed upwards.  The remaining one can't be moved, though.
-       pshufd  xmm1, xmm1, SHUF(0, 3, 2, 1)
+       pshufd  xmm1, xmm1, SHUF(1, 2, 3, 0)
 
        // Apply the diagonal quarterround to each of the columns
        // simultaneously.
@@ -207,9 +215,9 @@ FUNC(chacha_core_x86ish_sse2)
 
        // c += d; b ^= c; b <<<=  7
        paddd   xmm2, xmm3
-        pshufd xmm3, xmm3, SHUF(0, 3, 2, 1)
+        pshufd xmm3, xmm3, SHUF(1, 2, 3, 0)
        pxor    xmm1, xmm2
-        pshufd xmm2, xmm2, SHUF(1, 0, 3, 2)
+        pshufd xmm2, xmm2, SHUF(2, 3, 0, 1)
        movdqa  xmm4, xmm1
        pslld   xmm1, 7
        psrld   xmm4, 25
@@ -218,7 +226,7 @@ FUNC(chacha_core_x86ish_sse2)
        // Finally, finish off undoing the transpose, and we're done for this
        // doubleround.  Again, most of this was done above so we don't have
        // to wait for the shuffles.
-       pshufd  xmm1, xmm1, SHUF(2, 1, 0, 3)
+       pshufd  xmm1, xmm1, SHUF(3, 0, 1, 2)
 
        // Decrement the loop counter and see if we should go round again.
        sub     NR, 2
index f70ee9f..90a4c67 100644 (file)
@@ -41,6 +41,7 @@
 #include "grand.h"
 #include "keysz.h"
 #include "paranoia.h"
+#include "rsvr.h"
 
 /*----- Global variables --------------------------------------------------*/
 
@@ -72,6 +73,7 @@ static void simple_core(unsigned r, const chacha_matrix src,
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 extern core__functype chacha_core_x86ish_sse2;
+extern core__functype chacha_core_x86ish_avx;
 #endif
 
 #if CPUFAM_ARMEL
@@ -85,6 +87,8 @@ extern core__functype chacha_core_arm64;
 static core__functype *pick_core(void)
 {
 #if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(chacha_core, chacha_core_x86ish_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(chacha_core, chacha_core_x86ish_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
@@ -150,6 +154,8 @@ static void populate(chacha_matrix a, const void *key, size_t ksz)
 
 /*----- ChaCha implementation ---------------------------------------------*/
 
+static const octet zerononce[XCHACHA_NONCESZ];
+
 /* --- @chacha_init@ --- *
  *
  * Arguments:  @chacha_ctx *ctx@ = context to fill in
@@ -165,8 +171,6 @@ static void populate(chacha_matrix a, const void *key, size_t ksz)
 void chacha_init(chacha_ctx *ctx, const void *key, size_t ksz,
                  const void *nonce)
 {
-  static const octet zerononce[CHACHA_NONCESZ];
-
   populate(ctx->a, key, ksz);
   chacha_setnonce(ctx, nonce ? nonce : zerononce);
 }
@@ -222,7 +226,7 @@ void chacha_seek(chacha_ctx *ctx, unsigned long i)
 void chacha_seeku64(chacha_ctx *ctx, kludge64 i)
 {
   ctx->a[12] = LO64(i); ctx->a[13] = HI64(i);
-  ctx->bufi = CHACHA_OUTSZ;
+  ctx->off = CHACHA_OUTSZ;
 }
 
 void chacha_seek_ietf(chacha_ctx *ctx, uint32 i)
@@ -262,6 +266,8 @@ uint32 chacha_tell_ietf(chacha_ctx *ctx)
  *             to @dest@.
  */
 
+static const rsvr_policy policy = { 0, CHACHA_OUTSZ, CHACHA_OUTSZ };
+
 #define CHACHA_ENCRYPT(r, ctx, src, dest, sz)                          \
   chacha##r##_encrypt(ctx, src, dest, sz)
 #define DEFENCRYPT(r)                                                  \
@@ -271,41 +277,40 @@ uint32 chacha_tell_ietf(chacha_ctx *ctx)
     chacha_matrix b;                                                   \
     const octet *s = src;                                              \
     octet *d = dest;                                                   \
-    size_t n;                                                          \
+    rsvr_plan plan;                                                    \
     kludge64 pos, delta;                                               \
                                                                        \
-    SALSA20_OUTBUF(ctx, d, s, sz);                                     \
-    if (!sz) return;                                                   \
-                                                                       \
-    if (!dest) {                                                       \
-      n = sz/CHACHA_OUTSZ;                                             \
-      pos = chacha_tellu64(ctx);                                       \
-      ASSIGN64(delta, n);                                              \
-      ADD64(pos, pos, delta);                                          \
-      chacha_seeku64(ctx, pos);                                                \
-      sz = sz%CHACHA_OUTSZ;                                            \
-    } else if (!src) {                                                 \
-      while (sz >= CHACHA_OUTSZ) {                                     \
-       core(r, ctx->a, b);                                             \
-       CHACHA_STEP(ctx->a);                                            \
-       SALSA20_GENFULL(b, d);                                          \
-       sz -= CHACHA_OUTSZ;                                             \
+    rsvr_mkplan(&plan, &policy, ctx->off, sz);                         \
+                                                                       \
+    if (plan.head) {                                                   \
+      if (!ctx->off) {                                                 \
+       core(r, ctx->a, b); CHACHA_STEP(ctx->a);                        \
+       SALSA20_PREPBUF(ctx, b);                                        \
       }                                                                        \
-    } else {                                                           \
-      while (sz >= CHACHA_OUTSZ) {                                     \
-       core(r, ctx->a, b);                                             \
-       CHACHA_STEP(ctx->a);                                            \
-       SALSA20_MIXFULL(b, d, s);                                       \
-       sz -= CHACHA_OUTSZ;                                             \
+      SALSA20_OUTBUF(ctx, d, s, plan.head);                            \
+    }                                                                  \
+                                                                       \
+    ctx->off -= plan.from_rsvr;                                                \
+                                                                       \
+    if (!d) {                                                          \
+      if (plan.from_input) {                                           \
+       pos = chacha_tellu64(ctx);                                      \
+       ASSIGN64(delta, plan.from_input/SALSA20_OUTSZ);                 \
+       ADD64(pos, pos, delta);                                         \
+       chacha_seeku64(ctx, pos);                                       \
       }                                                                        \
+    } else if (!s) while (plan.from_input) {                           \
+      core(r, ctx->a, b); CHACHA_STEP(ctx->a);                         \
+      SALSA20_GENFULL(b, d); plan.from_input -= CHACHA_OUTSZ;          \
+    } else while (plan.from_input) {                                   \
+      core(r, ctx->a, b); CHACHA_STEP(ctx->a);                         \
+      SALSA20_MIXFULL(b, d, s); plan.from_input -= CHACHA_OUTSZ;       \
     }                                                                  \
                                                                        \
-    if (sz) {                                                          \
-      core(r, ctx->a, b);                                              \
-      CHACHA_STEP(ctx->a);                                             \
+    if (plan.tail) {                                                   \
+      core(r, ctx->a, b); CHACHA_STEP(ctx->a);                         \
       SALSA20_PREPBUF(ctx, b);                                         \
-      SALSA20_OUTBUF(ctx, d, s, sz);                                   \
-      assert(!sz);                                                     \
+      SALSA20_OUTBUF(ctx, d, s, plan.tail);                            \
     }                                                                  \
   }
 CHACHA_VARS(DEFENCRYPT)
@@ -401,8 +406,6 @@ CHACHA_VARS(DEFHCHACHA)
   void XCHACHA_INIT(r, XCHACHA_CTX(r) *ctx,                            \
                    const void *key, size_t ksz, const void *nonce)     \
   {                                                                    \
-    static const octet zerononce[XCHACHA_NONCESZ];                     \
-                                                                       \
     populate(ctx->k, key, ksz);                                                \
     ctx->s.a[ 0] = CHACHA_A256;                                                \
     ctx->s.a[ 1] = CHACHA_B256;                                                \
index 994cfa2..6c380dc 100644 (file)
@@ -64,8 +64,8 @@ typedef uint32 chacha_matrix[16];
 
 typedef struct chacha_ctx {
   chacha_matrix a;
-  octet buf[CHACHA_OUTSZ];
-  size_t bufi;
+  octet b[CHACHA_OUTSZ];
+  unsigned off;
 } chacha_ctx;
 
 #define XCHACHA_DEFCTX(name)                                           \
@@ -89,8 +89,8 @@ XCHACHA_DEFCTX(xchacha8_ctx);
  */
 
 extern void chacha_init(chacha_ctx */*ctx*/,
-                        const void */*key*/, size_t /*ksz*/,
-                        const void */*nonce*/);
+                       const void */*key*/, size_t /*ksz*/,
+                       const void */*nonce*/);
 
 /* --- @chacha_setnonce{,_ietf}@ --- *
  *
diff --git a/symm/cmac-def.h b/symm/cmac-def.h
new file mode 100644 (file)
index 0000000..701d3b5
--- /dev/null
@@ -0,0 +1,406 @@
+/* -*-c-*-
+ *
+ * The CMAC message-authentication code
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_CMAC_DEF_H
+#define CATACOMB_CMAC_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_BLKC_H
+#  include "blkc.h"
+#endif
+
+#ifndef CATACOMB_GMAC_H
+#  include "gmac.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+/*----- Low-level OMAC definitions ----------------------------------------*/
+
+/* --- @OMAC_BLOCK@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *             @pre_ctx *k@ = pointer to expanded blockcipher key
+ *             @uint32 *a@ = accumulator state to update
+ *             @octet *p@ = pointer to input block to accumulate
+ *
+ * Use:                Update the state @a@ from the input block @p@.
+ */
+
+#define OMAC_BLOCK(PRE, pre, k, a, p) do {                             \
+  pre##_ctx *_k = (k); uint32 *_a = (a); const octet *_pp = (p);       \
+  BLKC_XLOAD(PRE, _a, _pp); pre##_eblk(_k, _a, _a);                    \
+} while (0)
+
+/* --- @OMAC_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates low-level implementation for the OMAC message-
+ *             authentication mode.
+ */
+
+#define OMAC_DEF(PRE, pre)                                             \
+                                                                       \
+/* Buffering policy for OMAC. */                                       \
+const rsvr_policy pre##_omacpolicy =                                   \
+  { RSVRF_FULL, PRE##_BLKSZ, PRE##_BLKSZ };                            \
+                                                                       \
+/* --- @pre_omacmasks@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_ctx *k@ = pointer to expanded blockcipher key      \
+ *             @uint32 *m0, *m1@ = buffers to store the masks          \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initialize the OMAC masks.  The mask buffers are        \
+ *             @PRE_BLKSZ/4@ words long.  The mmask @m0@ is applied to \
+ *             messages which are a whole number of blocks long; @m1@  \
+ *             is applied to messages with an incomplete final block,  \
+ *             following the 10* padding.                              \
+ */                                                                    \
+                                                                       \
+void pre##_omacmasks(pre##_ctx *k, uint32 *m0, uint32 *m1)             \
+{                                                                      \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+                                                                       \
+  BLKC_ZERO(PRE, t); pre##_eblk(k, t, t);                              \
+  BLKC_BLSHIFT(PRE, IRRED, m0, t);                                     \
+  BLKC_BLSHIFT(PRE, IRRED, m1, m0);                                    \
+}                                                                      \
+                                                                       \
+/* --- @pre_omacdone@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ctx *k@ = pointer to expanded blockcipher key      \
+ *             @const uint32 *m0, *m1@ = masks                         \
+ *             @uint32 *a@ = accumulator state to update               \
+ *             @octet *p@ = pointer to input buffer (clobbered)        \
+ *             @unsigned n@ = size of input buffer (no more than       \
+ *                     @PRE_BLKSZ@)                                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Update and finalize the OMAC hash state with the last   \
+ *             few bytes of input.  The final tag is left in @a@.      \
+ */                                                                    \
+                                                                       \
+void pre##_omacdone(pre##_ctx *k, const uint32 *m0, const uint32 *m1,  \
+                   uint32 *a, octet *p, unsigned n)                    \
+{                                                                      \
+  /* Do any necessary padding and apply the appropriate mask to the    \
+   * accumulator.                                                      \
+   */                                                                  \
+  if (n == PRE##_BLKSZ)                                                        \
+    BLKC_XMOVE(PRE, a, m0);                                            \
+  else {                                                               \
+    p[n] = 0x80; memset(p + n + 1, 0, PRE##_BLKSZ - n - 1);            \
+    BLKC_XMOVE(PRE, a, m1);                                            \
+  }                                                                    \
+                                                                       \
+  /* Fetch the buffer contents and cycle the block cipher one last     \
+   * time.                                                             \
+   */                                                                  \
+  BLKC_XLOAD(PRE, a, p);                                               \
+  pre##_eblk(k, a, a);                                                 \
+}
+
+/*----- Properly cooked CMAC ----------------------------------------------*/
+
+/* --- @CMAC_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates an implementation for the CMAC message-authentication
+ *             mode.
+ */
+
+#define CMAC_DEF(PRE, pre) CMAC_DEFX(PRE, pre, #pre, #pre)
+
+#define CMAC_DEFX(PRE, pre, name, fname)                               \
+                                                                       \
+OMAC_DEF(PRE, pre)                                                     \
+                                                                       \
+/* --- @pre_cmacsetkey@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_cmackey *key@ = pointer to CMAC key block          \
+ *             @ocnst void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes a CMAC key.  This can be used for several   \
+ *             MAC operations.                                         \
+ */                                                                    \
+                                                                       \
+void pre##_cmacsetkey(pre##_cmackey *key, const void *k, size_t ksz)   \
+{                                                                      \
+  pre##_init(&key->ctx, k, ksz);                                       \
+  pre##_omacmasks(&key->ctx, key->m0, key->m1);                                \
+}                                                                      \
+                                                                       \
+/* --- @pre##_cmacinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_cmacctx *ctx@ = pointer to context block           \
+ *             @pre_cmackey *k@ = key block                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes a CMAC context ready to process a message.  \
+ *             It's not necessary to keep the key around.              \
+ */                                                                    \
+                                                                       \
+void pre##_cmacinit(pre##_cmacctx *ctx, const pre##_cmackey *k)                \
+  { ctx->k = *k; ctx->off = 0; BLKC_ZERO(PRE, ctx->a); }               \
+                                                                       \
+/* --- @pre_cmachash@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_cmacctx *ctx@ = pointer to CMAC context block      \
+ *             @ocnst void *p@ = pointer to message buffer             \
+ *             @size_t sz@ = size of message buffer                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Hashes some input data.                                 \
+ */                                                                    \
+                                                                       \
+void pre##_cmachash(pre##_cmacctx *ctx, const void *p, size_t sz)      \
+{                                                                      \
+  rsvr_state st;                                                       \
+  const octet *q;                                                      \
+                                                                       \
+  rsvr_setup(&st, &pre##_omacpolicy, ctx->b, &ctx->off, p, sz);                \
+  RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0)          \
+    OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->a, q);                      \
+}                                                                      \
+                                                                       \
+/* --- @pre_cmacdone@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_cmacctx *ctx@ = pointer to CMAC context block      \
+ *             @void *t@ = where to write the tag                      \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes a MAC operation and produces the tag.  The     \
+ *             context is clobbered and can't be used for anything     \
+ *             useful any more.                                        \
+ */                                                                    \
+                                                                       \
+void pre##_cmacdone(pre##_cmacctx *ctx, void *t)                       \
+{                                                                      \
+  pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1,                    \
+                ctx->a, ctx->b, ctx->off);                             \
+  BLKC_STORE(PRE, t, ctx->a);                                          \
+}                                                                      \
+                                                                       \
+/* --- Generic MAC interface --- */                                    \
+                                                                       \
+static const gmac_ops gkops;                                           \
+static const ghash_ops gops;                                           \
+                                                                       \
+typedef struct gkctx {                                                 \
+  gmac m;                                                              \
+  pre##_cmackey k;                                                     \
+} gkctx;                                                               \
+                                                                       \
+typedef struct gctx {                                                  \
+  ghash h;                                                             \
+  pre##_cmacctx c;                                                     \
+  octet buf[PRE##_BLKSZ];                                              \
+} gctx;                                                                        \
+                                                                       \
+static ghash *gkinit(gmac *m)                                          \
+{                                                                      \
+  gkctx *gk = (gkctx *)m;                                              \
+  gctx *g = S_CREATE(gctx);                                            \
+  g->h.ops = &gops;                                                    \
+  pre##_cmacinit(&g->c, &gk->k);                                       \
+  return (&g->h);                                                      \
+}                                                                      \
+                                                                       \
+static gmac *gkey(const void *k, size_t sz)                            \
+{                                                                      \
+  gkctx *gk = S_CREATE(gkctx);                                         \
+  gk->m.ops = &gkops;                                                  \
+  pre##_cmacsetkey(&gk->k, k, sz);                                     \
+  return (&gk->m);                                                     \
+}                                                                      \
+                                                                       \
+static void ghhash(ghash *h, const void *p, size_t sz)                 \
+  { gctx *g = (gctx *)h; pre##_cmachash(&g->c, p, sz); }               \
+                                                                       \
+static octet *ghdone(ghash *h, void *buf)                              \
+{                                                                      \
+  gctx *g = (gctx *)h;                                                 \
+  if (!buf) buf = g->buf;                                              \
+  pre##_cmacdone(&g->c, buf);                                          \
+  return (buf);                                                                \
+}                                                                      \
+                                                                       \
+static ghash *ghcopy(ghash *h)                                         \
+{                                                                      \
+  gctx *g = (gctx *)h;                                                 \
+  gctx *gg = S_CREATE(gctx);                                           \
+  memcpy(gg, g, sizeof(gctx));                                         \
+  return (&gg->h);                                                     \
+}                                                                      \
+                                                                       \
+static void ghdestroy(ghash *h)                                                \
+  { gctx *g = (gctx *)h; BURN(*g); S_DESTROY(g); }                     \
+                                                                       \
+static void gkdestroy(gmac *m)                                         \
+  { gkctx *gk = (gkctx *)m; BURN(*gk); S_DESTROY(gk); }                        \
+                                                                       \
+static ghash *ghinit(void)                                             \
+{                                                                      \
+  assert(((void)"Attempt to instantiate an unkeyed MAC", 0));          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+const gcmac pre##_cmac =                                               \
+  { name "-cmac", PRE##_BLKSZ, pre##_keysz, gkey };                    \
+static const gmac_ops gkops = { &pre##_cmac, gkinit, gkdestroy };      \
+static const gchash gch = { name "-cmac", PRE##_BLKSZ, ghinit };       \
+static const ghash_ops gops =                                          \
+  { &gch, ghhash, ghdone, ghdestroy, ghcopy };                         \
+                                                                       \
+CMAC_TESTX(PRE, pre, name, fname)
+
+#define CMAC_TEST(PRE, pre) HMAC_TESTX(PRE, pre, #pre, #pre)
+
+/* --- @CMAC_TEST@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Standard test rig for CMAC functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define CMAC_TESTX(PRE, pre, name, fname)                              \
+                                                                       \
+static int macverify(dstr *v)                                          \
+{                                                                      \
+  pre##_cmacctx cctx;                                                  \
+  pre##_cmackey ckey;                                                  \
+  int ok = 1;                                                          \
+  int i;                                                               \
+  octet *p;                                                            \
+  int szs[] = { 1, 7, 192, -1, 0 }, *ip;                               \
+  size_t csz;                                                          \
+  dstr d;                                                              \
+                                                                       \
+  dstr_create(&d);                                                     \
+  dstr_ensure(&d, PRE##_BLKSZ);                                                \
+  d.len = PRE##_BLKSZ;                                                 \
+                                                                       \
+  pre##_cmacsetkey(&ckey, v[0].buf, v[0].len);                         \
+                                                                       \
+  for (ip = szs; *ip; ip++) {                                          \
+    i = *ip;                                                           \
+    csz = v[1].len;                                                    \
+    if (i == -1)                                                       \
+      i = csz;                                                         \
+    if (i > csz)                                                       \
+      continue;                                                                \
+    p = (octet *)v[1].buf;                                             \
+    pre##_cmacinit(&cctx, &ckey);                                      \
+    while (csz) {                                                      \
+      if (i > csz)                                                     \
+       i = csz;                                                        \
+      pre##_cmachash(&cctx, p, i);                                     \
+      p += i;                                                          \
+      csz -= i;                                                                \
+    }                                                                  \
+    pre##_cmacdone(&cctx, d.buf);                                      \
+    if (memcmp(d.buf, v[2].buf, PRE##_BLKSZ) != 0) {                   \
+      printf("\nfail:\n\tstep = %i\n\tkey = ", *ip);                   \
+      type_hex.dump(&v[0], stdout);                                    \
+      fputs("\n\tinput = ", stdout);                                   \
+      type_hex.dump(&v[1], stdout);                                    \
+      fputs("\n\texpected = ", stdout);                                        \
+      type_hex.dump(&v[2], stdout);                                    \
+      fputs("\n\tcomputed = ", stdout);                                        \
+      type_hex.dump(&d, stdout);                                       \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  dstr_destroy(&d);                                                    \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static test_chunk macdefs[] = {                                                \
+  { name "-cmac", macverify,                                           \
+    { &type_hex, &type_hex, &type_hex, 0 } },                          \
+  { 0, 0, { 0 } }                                                      \
+};                                                                     \
+                                                                       \
+int main(int argc, char *argv[])                                       \
+{                                                                      \
+  ego(argv[0]);                                                                \
+  test_run(argc, argv, macdefs, SRCDIR"/t/" fname);                    \
+  return (0);                                                          \
+}
+
+#else
+#  define CMAC_TESTX(PRE, pre, name, fname)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/cmac.h b/symm/cmac.h
new file mode 100644 (file)
index 0000000..95b047e
--- /dev/null
@@ -0,0 +1,210 @@
+/* -*-c-*-
+ *
+ * The CMAC message-authentication code
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Notes on CMAC -----------------------------------------------------*
+ *
+ * CMAC was designed in 2003 by Tetsu Iwata and Kaoru Kurosawa as a reliable
+ * general purpose message-authentication code based on CBC-MAC.  CBC-MAC's
+ * deficiencies have been well known since at least 2000 when Bellare,
+ * Kilian, and Rogaway proved its security on constant-length messages.
+ * Black and Rogaway in 2000 described a number of three-key constructions
+ * for extending CBC-MAC's domain securely to arbitrary strings, culminating
+ * in a mode they named `XCBC', which uses a blockcipher key and two XOR
+ * masks.  Iwata and Kurosawa's original proposal, named `OMAC', refined XCBC
+ * by deriving the masks from the key, producing a `one-key MAC'.  Bellare,
+ * Rogaway, and Wagner slightly simplified the way the masks were derived
+ * when they used OMAC as a part of their EAX authenticated-encryption mode,
+ * and this change was adopted by NIST when they standardized OMAC, under the
+ * name `CMAC', in SP800-38B.
+ *
+ * NIST specify CMAC only for 64- and 128-bit blockciphers.  This
+ * implementation extends it to other lengths in the obvious way.
+ */
+
+#ifndef CATACOMB_CMAC_H
+#define CATACOMB_CMAC_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_GMAC_H
+#  include "gmac.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+/*----- Low-level OMAC declarations ---------------------------------------*/
+
+/* --- @OMAC_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Defines low-level implementation for the OMAC message-
+ *             authentication mode.
+ */
+
+#define OMAC_DECL(PRE, pre)                                            \
+                                                                       \
+/* Buffering policy for OMAC. */                                       \
+extern const rsvr_policy pre##_omacpolicy;                             \
+                                                                       \
+/* --- @pre_omacmasks@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_ctx *k@ = pointer to expanded blockcipher key      \
+ *             @uint32 *m0, *m1@ = buffers to store the masks          \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initialize the OMAC masks.  The mask buffers are        \
+ *             @PRE_BLKSZ/4@ words long.  The mmask @m0@ is applied to \
+ *             messages which are a whole number of blocks long; @m1@  \
+ *             is applied to messages with an incomplete final block,  \
+ *             following the 10* padding.                              \
+ */                                                                    \
+                                                                       \
+extern void pre##_omacmasks(pre##_ctx */*k*/,                          \
+                           uint32 */*m0*/, uint32 */*m1*/);            \
+                                                                       \
+/* --- @pre_omacdone@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ctx *k@ = pointer to expanded blockcipher key      \
+ *             @const uint32 *m0, *m1@ = masks                         \
+ *             @uint32 *a@ = accumulator state to update               \
+ *             @octet *p@ = pointer to input buffer (clobbered)        \
+ *             @unsigned n@ = size of input buffer (no more than       \
+ *                     @PRE_BLKSZ@)                                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Update and finalize the OMAC hash state with the last   \
+ *             few bytes of input.  The final tag is left in @a@.      \
+ */                                                                    \
+                                                                       \
+extern void pre##_omacdone(pre##_ctx */*k*/,                           \
+                          const uint32 */*m0*/, const uint32 */*m1*/,  \
+                          uint32 */*a*/, octet */*p*/, unsigned /*n*/);
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @CMAC_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates declarations for CMAC message-authentication mode.
+ */
+
+#define CMAC_DECL(PRE, pre)                                            \
+                                                                       \
+OMAC_DECL(PRE, pre)                                                    \
+                                                                       \
+typedef struct pre##_cmackey {                                         \
+  pre##_ctx ctx;                       /* Underlying cipher context */ \
+  uint32 m0[PRE##_BLKSZ/4], m1[PRE##_BLKSZ/4]; /* Final block masks */ \
+} pre##_cmackey;                                                       \
+                                                                       \
+typedef struct pre##_cmacctx {                                         \
+  pre##_cmackey k;                     /* Processed key material */    \
+  uint32 a[PRE##_BLKSZ/4];             /* Chaining state */            \
+  octet b[PRE##_BLKSZ];                        /* Input buffer */              \
+  unsigned off;                                /* Offset into buffered data */ \
+} pre##_cmacctx;                                                       \
+                                                                       \
+/* --- @pre_cmacsetkey@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_cmackey *key@ = pointer to CMAC key block          \
+ *             @ocnst void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes a CMAC key.  This can be used for several   \
+ *             MAC operations.                                         \
+ */                                                                    \
+                                                                       \
+extern void pre##_cmacsetkey(pre##_cmackey */*key*/,                   \
+                            const void */*k*/, size_t /*ksz*/);        \
+                                                                       \
+/* --- @pre##_cmacinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_cmacctx *ctx@ = pointer to context block           \
+ *             @pre_cmackey *k@ = key block                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes a CMAC context ready to process a message.  \
+ *             It's not necessary to keep the key around.              \
+ */                                                                    \
+                                                                       \
+extern void pre##_cmacinit(pre##_cmacctx */*ctx*/,                     \
+                          const pre##_cmackey */*k*/);                 \
+                                                                       \
+/* --- @pre_cmachash@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_cmacctx *ctx@ = pointer to CMAC context block      \
+ *             @ocnst void *p@ = pointer to message buffer             \
+ *             @size_t sz@ = size of message buffer                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Hashes some input data.                                 \
+ */                                                                    \
+                                                                       \
+extern void pre##_cmachash(pre##_cmacctx */*ctx*/,                     \
+                          const void */*p*/, size_t /*sz*/);           \
+                                                                       \
+/* --- @pre_cmacdone@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_cmacctx *ctx@ = pointer to CMAC context block      \
+ *             @void *t@ = where to write the tag                      \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes a MAC operation and produces the tag.          \
+ */                                                                    \
+                                                                       \
+extern void pre##_cmacdone(pre##_cmacctx */*ctx*/, void */*t*/);       \
+                                                                       \
+/* --- Generic MAC interface --- */                                    \
+                                                                       \
+extern const gcmac pre##_cmac;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index ad955db..3c949c7 100644 (file)
 #  include "paranoia.h"
 #endif
 
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
 /*----- Macros ------------------------------------------------------------*/
 
 /* --- @COUNTER_DEF@ --- *
@@ -84,9 +88,7 @@
  */                                                                    \
                                                                        \
 void pre##_countergetiv(const pre##_counterctx *ctx, void *iv)         \
-{                                                                      \
-  BLKC_STORE(PRE, iv, ctx->n);                                         \
-}                                                                      \
+  { BLKC_STORE(PRE, iv, ctx->c); }                                     \
                                                                        \
 /* --- @pre_countersetiv@ --- *                                                \
  *                                                                     \
@@ -99,10 +101,7 @@ void pre##_countergetiv(const pre##_counterctx *ctx, void *iv)              \
  */                                                                    \
                                                                        \
 void pre##_countersetiv(pre##_counterctx *ctx, const void *iv)         \
-{                                                                      \
-  BLKC_LOAD(PRE, ctx->n, iv);                                          \
-  ctx->off = PRE##_BLKSZ;                                              \
-}                                                                      \
+  { BLKC_LOAD(PRE, ctx->c, iv); ctx->off = PRE##_BLKSZ; }              \
                                                                        \
 /* --- @pre_counterbdry@ --- *                                         \
  *                                                                     \
@@ -115,10 +114,7 @@ void pre##_countersetiv(pre##_counterctx *ctx, const void *iv)             \
  */                                                                    \
                                                                        \
 void pre##_counterbdry(pre##_counterctx *ctx)                          \
-{                                                                      \
-  BLKC_STEP(PRE, ctx->n);                                              \
-  ctx->off = PRE##_BLKSZ;                                              \
-}                                                                      \
+  { BLKC_STEP(PRE, ctx->c); ctx->off = PRE##_BLKSZ; }                  \
                                                                        \
 /* --- @pre_countersetkey@ --- *                                       \
  *                                                                     \
@@ -131,9 +127,7 @@ void pre##_counterbdry(pre##_counterctx *ctx)                               \
  */                                                                    \
                                                                        \
 void pre##_countersetkey(pre##_counterctx *ctx, const pre##_ctx *k)    \
-{                                                                      \
-  ctx->ctx = *k;                                                       \
-}                                                                      \
+  { ctx->ctx = *k; }                                                   \
                                                                        \
 /* --- @pre_counterinit@ --- *                                         \
  *                                                                     \
@@ -156,6 +150,7 @@ void pre##_counterinit(pre##_counterctx *ctx,                               \
                       const void *iv)                                  \
 {                                                                      \
   static const octet zero[PRE##_BLKSZ] = { 0 };                                \
+                                                                       \
   pre##_init(&ctx->ctx, key, sz);                                      \
   pre##_countersetiv(ctx, iv ? iv : zero);                             \
 }                                                                      \
@@ -176,81 +171,66 @@ void pre##_counterinit(pre##_counterctx *ctx,                             \
  *             use the cipher as a random data generator.              \
  */                                                                    \
                                                                        \
+static const rsvr_policy pre##_counterpolicy =                         \
+  { 0, PRE##_BLKSZ, PRE##_BLKSZ };                                     \
+                                                                       \
 void pre##_counterencrypt(pre##_counterctx *ctx,                       \
                          const void *src, void *dest,                  \
                          size_t sz)                                    \
 {                                                                      \
-  const octet *s = src;                                                        \
+  rsvr_plan plan;                                                      \
+  const octet *s = src, *p;                                            \
   octet *d = dest;                                                     \
-  unsigned off = ctx->off;                                             \
-                                                                       \
-  /* --- Empty blocks are trivial --- */                               \
-                                                                       \
-  if (!sz)                                                             \
-    return;                                                            \
-                                                                       \
-  /* --- If I can deal with the block from my buffer, do that --- */   \
-                                                                       \
-  if (sz < PRE##_BLKSZ - off)                                          \
-    goto small;                                                                \
-                                                                       \
-  /* --- Finish off what's left in my buffer --- */                    \
-                                                                       \
-  if (!d)                                                              \
-    sz -= PRE##_BLKSZ - off;                                           \
-  else {                                                               \
-    while (off < PRE##_BLKSZ) {                                                \
-      register octet x = s ? *s++ : 0;                                 \
-      *d++ = ctx->buf[off++] ^ x;                                      \
-      sz--;                                                            \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+                                                                       \
+  /* Construct a plan and prepare to follow through. */                        \
+  rsvr_mkplan(&plan, &pre##_counterpolicy, ctx->off, sz);              \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the chunk is small        \
+   * enough, then this will be the only portion.  If the buffer is     \
+   * currently empty, then we must prepare it.                         \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c);                \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
     }                                                                  \
+    p = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    if (!d) /* nothing to do */;                                       \
+    else if (!s) { memcpy(d, p, plan.head); d += plan.head; }          \
+    else while (plan.head--) *d++ = *s++ ^ *p++;                       \
   }                                                                    \
                                                                        \
-  /* --- Main encryption loop --- */                                   \
-                                                                       \
-  {                                                                    \
-    uint32 n[PRE##_BLKSZ / 4];                                         \
-                                                                       \
-    for (;;) {                                                         \
-      pre##_eblk(&ctx->ctx, ctx->n, n);                                        \
-      BLKC_STEP(PRE, ctx->n);                                          \
-      if (sz < PRE##_BLKSZ)                                            \
-       break;                                                          \
-      if (d) {                                                         \
-       if (!s)                                                         \
-         BLKC_STORE(PRE, d, n);                                        \
-       else {                                                          \
-         uint32 x[PRE##_BLKSZ / 4];                                    \
-         BLKC_LOAD(PRE, x, s);                                         \
-         BLKC_XSTORE(PRE, d, n, x);                                    \
-         s += PRE##_BLKSZ;                                             \
-       }                                                               \
-       d += PRE##_BLKSZ;                                               \
-      }                                                                        \
-      sz -= PRE##_BLKSZ;                                               \
-    }                                                                  \
+  /* If the buffer is all used, then reset it ready for next time. */  \
+  ctx->off -= plan.from_rsvr;                                          \
                                                                        \
-    BLKC_STORE(PRE, ctx->buf, n);                                      \
-    off = 0;                                                           \
+  /* Handle multiple whole blocks. */                                  \
+  if (!d)                                                              \
+    BLKC_ADD(PRE, ctx->c, plan.from_input/PRE##_BLKSZ);                        \
+  else if (!s) while (plan.from_input) {                               \
+    pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c);          \
+    BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ;                           \
+    plan.from_input -= PRE##_BLKSZ;                                    \
+  } else while (plan.from_input) {                                     \
+    pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c);          \
+    BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ;                           \
+    BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ;                           \
+    plan.from_input -= PRE##_BLKSZ;                                    \
   }                                                                    \
                                                                        \
-  /* --- Tidying up the tail end --- */                                        \
-                                                                       \
-  if (sz) {                                                            \
-  small:                                                               \
-    if (!d)                                                            \
-      off += sz;                                                       \
-    else do {                                                          \
-      register octet x = s ? *s++ : 0;                                 \
-      *d++ = ctx->buf[off++] ^ x;                                      \
-      sz--;                                                            \
-    } while (sz);                                                      \
+  /* Final portion.  Note that the buffer must be empty if there is a  \
+   * tail, since otherwise the input data would have been part of the  \
+   * head portion instad. */                                           \
+  if (!plan.tail)                                                      \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+  else {                                                               \
+    pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c);          \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    p = ctx->b; ctx->off += plan.tail;                                 \
+    if (!d) /* nothing to do */;                                       \
+    else if (!s) { memcpy(d, p, plan.tail); d += plan.tail; }          \
+    else while (plan.tail--) *d++ = *s++ ^ *p++;                       \
   }                                                                    \
-                                                                       \
-  /* --- Done --- */                                                   \
-                                                                       \
-  ctx->off = off;                                                      \
-  return;                                                              \
 }                                                                      \
                                                                        \
 /* --- Generic cipher interface --- */                                 \
@@ -271,29 +251,16 @@ static gcipher *ginit(const void *k, size_t sz)                           \
 }                                                                      \
                                                                        \
 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_counterencrypt(&g->k, s, t, sz);                               \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_counterencrypt(&g->k, s, t, sz); }      \
                                                                        \
 static void gdestroy(gcipher *c)                                       \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  BURN(*g);                                                            \
-  S_DESTROY(g);                                                                \
-}                                                                      \
+  { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }                     \
                                                                        \
 static void gsetiv(gcipher *c, const void *iv)                         \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_countersetiv(&g->k, iv);                                       \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_countersetiv(&g->k, iv); }              \
                                                                        \
 static void gbdry(gcipher *c)                                          \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_counterbdry(&g->k);                                            \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_counterbdry(&g->k); }                   \
                                                                        \
 static const gcipher_ops gops = {                                      \
   &pre##_counter,                                                      \
@@ -343,11 +310,11 @@ static int grmisc(grand *r, unsigned op, ...)                             \
       }                                                                        \
       break;                                                           \
     case GRAND_SEEDINT:                                                        \
-      BLKC_SET(PRE, g->k.n, va_arg(ap, unsigned));                     \
+      BLKC_SET(PRE, g->k.c, va_arg(ap, unsigned));                     \
       g->k.off = PRE##_BLKSZ;                                          \
       break;                                                           \
     case GRAND_SEEDUINT32:                                             \
-      BLKC_SET(PRE, g->k.n, va_arg(ap, uint32));                       \
+      BLKC_SET(PRE, g->k.c, va_arg(ap, uint32));                       \
       g->k.off = PRE##_BLKSZ;                                          \
       break;                                                           \
     case GRAND_SEEDBLOCK: {                                            \
@@ -391,10 +358,7 @@ static uint32 grword(grand *r)                                             \
 }                                                                      \
                                                                        \
 static void grfill(grand *r, void *p, size_t sz)                       \
-{                                                                      \
-  grctx *g = (grctx *)r;                                               \
-  pre##_counterencrypt(&g->k, 0, p, sz);                               \
-}                                                                      \
+  { grctx *g = (grctx *)r; pre##_counterencrypt(&g->k, 0, p, sz); }    \
                                                                        \
 static const grand_ops grops = {                                       \
   name "-counter",                                                     \
@@ -430,9 +394,7 @@ COUNTER_TESTX(PRE, pre, name, fname)
 
 #ifdef TEST_RIG
 
-#include <stdio.h>
-
-#include "daftstory.h"
+#include "modes-test.h"
 
 /* --- @COUNTER_TEST@ --- *
  *
@@ -443,85 +405,24 @@ COUNTER_TESTX(PRE, pre, name, fname)
 
 #define COUNTER_TESTX(PRE, pre, name, fname)                           \
                                                                        \
-/* --- Initial plaintext for the test --- */                           \
-                                                                       \
-static const octet text[] = TEXT;                                      \
-                                                                       \
-/* --- Key and IV to use --- */                                                \
-                                                                       \
-static const octet key[] = KEY;                                                \
-static const octet iv[] = IV;                                          \
+static pre##_ctx key;                                                  \
+static pre##_counterctx ctx;                                           \
                                                                        \
-/* --- Buffers for encryption and decryption output --- */             \
+static void pre##_counter_test_setup(const octet *k, size_t ksz)       \
+  { pre##_init(&key, k, ksz); pre##_countersetkey(&ctx, &key); }       \
                                                                        \
-static octet ct[sizeof(text)];                                         \
-static octet pt[sizeof(text)];                                         \
+static void pre##_counter_test_reset(const octet *iv)                  \
+  { pre##_countersetiv(&ctx, iv); }                                    \
                                                                        \
-static void hexdump(const octet *p, size_t sz, size_t off)             \
-{                                                                      \
-  const octet *q = p + sz;                                             \
-  for (sz = 0; p < q; p++, sz++) {                                     \
-    printf("%02x", *p);                                                        \
-    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
-      putchar(':');                                                    \
-  }                                                                    \
-}                                                                      \
+static void pre##_counter_test_enc(const octet *s, octet *d, size_t sz)        \
+  { pre##_counterencrypt(&ctx, s, d, sz); }                            \
                                                                        \
-int main(void)                                                         \
+int main(int argc, char *argv[])                                       \
 {                                                                      \
-  size_t sz = 0, rest;                                                 \
-  pre##_counterctx ctx;                                                        \
-  int status = 0;                                                      \
-  int done = 0;                                                                \
-  pre##_ctx k;                                                         \
-                                                                       \
-  size_t keysz = PRE##_KEYSZ ?                                         \
-    PRE##_KEYSZ : strlen((const char *)key);                           \
-                                                                       \
-  fputs(name "-counter: ", stdout);                                    \
-                                                                       \
-  pre##_init(&k, key, keysz);                                          \
-  pre##_countersetkey(&ctx, &k);                                       \
-                                                                       \
-  while (sz <= sizeof(text)) {                                         \
-    rest = sizeof(text) - sz;                                          \
-    memcpy(ct, text, sizeof(text));                                    \
-    pre##_countersetiv(&ctx, iv);                                      \
-    pre##_counterencrypt(&ctx, ct, ct, sz);                            \
-    pre##_counterencrypt(&ctx, ct + sz, ct + sz, rest);                        \
-    memcpy(pt, ct, sizeof(text));                                      \
-    pre##_countersetiv(&ctx, iv);                                      \
-    pre##_counterencrypt(&ctx, pt, pt, rest);                          \
-    pre##_counterencrypt(&ctx, pt + rest, pt + rest, sz);              \
-    if (memcmp(pt, text, sizeof(text)) == 0) {                         \
-      done++;                                                          \
-      if (sizeof(text) < 40 || done % 8 == 0)                          \
-       fputc('.', stdout);                                             \
-      if (done % 480 == 0)                                             \
-       fputs("\n\t", stdout);                                          \
-      fflush(stdout);                                                  \
-    } else {                                                           \
-      printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
-      status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
-       printf(", "); hexdump(text + sz, rest, sz);                     \
-       fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
-       printf(", "); hexdump(ct + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
-       printf(", "); hexdump(pt + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      fputc('\n', stdout);                                             \
-    }                                                                  \
-    if (sz < 63)                                                       \
-      sz++;                                                            \
-    else                                                               \
-      sz += 9;                                                         \
-  }                                                                    \
-                                                                       \
-  fputs(status ? " failed\n" : " ok\n", stdout);                       \
-  return (status);                                                     \
+  return test_encmode(fname "-counter", PRE##_KEYSZ, PRE##_BLKSZ, 1, 0,        \
+                     pre##_counter_test_setup, pre##_counter_test_reset, \
+                     pre##_counter_test_enc, pre##_counter_test_enc,   \
+                     argc, argv);                                      \
 }
 
 #else
index 7e07b3c..418f148 100644 (file)
@@ -62,8 +62,8 @@
 typedef struct pre##_counterctx {                                      \
   pre##_ctx ctx;                       /* Underlying cipher context */ \
   unsigned off;                                /* Current offset in buffer */  \
-  octet buf[PRE##_BLKSZ];              /* Output buffer */             \
-  uint32 n[PRE##_BLKSZ / 4];           /* Counter */                   \
+  octet b[PRE##_BLKSZ];                        /* Output buffer */             \
+  uint32 c[PRE##_BLKSZ / 4];           /* Counter */                   \
 } pre##_counterctx;                                                    \
                                                                        \
 /* --- @pre_countergetiv@ --- *                                                \
diff --git a/symm/daftstory.h b/symm/daftstory.h
deleted file mode 100644 (file)
index b4d6b58..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*-c-*-
- *
- * Daft story for use in test encryptions
- *
- * (c) 1999 Straylight/Edgeware
- */
-
-/*----- Licensing notice --------------------------------------------------*
- *
- * This file is part of Catacomb.
- *
- * Catacomb is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * Catacomb is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with Catacomb; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#ifndef CATACOMB_DAFTSTORY_H
-#define CATACOMB_DAFTSTORY_H
-
-#ifdef __cplusplus
-  extern "C" {
-#endif
-
-/*----- Macros ------------------------------------------------------------*/
-
-/* --- Don't ask --- */
-
-#ifdef SMALL_TEST
-#  define TEXT "A small piece of text for testing encryption."
-#else
-#  define STORY "\
-Once upon a time there were a beautiful princess, a slightly nutty wizard,\n\
-and a watermelon.  Now, the watermelon had decided that it probably wasn't\n\
-going to get very far with the princess unless it did something pretty\n\
-drastic.  So it asked the wizard to turn it into a handsome prince.\n\
-\n\
-At least, this is the way that the wizard viewed the situation.  He might\n\
-have just hallucinated it all; those mushrooms had looked ever so nice.\n\
-\n\
-Back to the point.  The watermelon had expressed its desire not to be a\n\
-watermelon any more.  And the wizard was probably tripping something quite\n\
-powerful.  He hunted around a bit for his staff, and mumbled something\n\
-that film directors would think of as sounding appropriately arcane and\n\
-mystical (but was, in fact, just the ingredients list for an ancient\n\
-remedy for athlete's foot) and *pop*.  Cooked watermelon.  Yuk.\n\
-\n\
-Later in the year, the princess tripped over the hem of her dress, fell\n\
-down a spiral staircase, and died.  The king ordered dressmakers to attach\n\
-safety warnings to long dresses.\n\
-\n\
-And the wizard?         Who cares?\n\
-"
-#  define TEXT STORY STORY
-#endif
-
-#define KEY "Penguins rule OK, rhubarb cauliflower"
-#define IV "EdgewareCatacomb, parsley, sage, rosemary and thyme"
-
-/*----- That's all, folks -------------------------------------------------*/
-
-#ifdef __cplusplus
-  }
-#endif
-
-#endif
diff --git a/symm/eax-def.h b/symm/eax-def.h
new file mode 100644 (file)
index 0000000..6e1c7ca
--- /dev/null
@@ -0,0 +1,850 @@
+/* -*-c-*-
+ *
+ * The EAX authenticated-encryption mode
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_EAX_DEF_H
+#define CATACOMB_EAX_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_BLKC_H
+#  include "blkc.h"
+#endif
+
+#ifndef CATACOMB_CT_H
+#  include "ct.h"
+#endif
+
+#ifndef CATACOMB_CMAC_H
+#  include "cmac.h"
+#endif
+
+#ifndef CATACOMB_CMAC_DEF_H
+#  include "cmac-def.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+#  include "keysz.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @EAX_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates an implementation for the EAX authenticated-
+ *             encryption mode.
+ */
+
+#define EAX_DEF(PRE, pre) EAX_DEFX(PRE, pre, #pre, #pre)
+
+#define EAX_DEFX(PRE, pre, name, fname)                                        \
+                                                                       \
+OMAC_DECL(PRE, pre)                                                    \
+                                                                       \
+const octet                                                            \
+  pre##_eaxnoncesz[] = { KSZ_ANY, PRE##_BLKSZ },                       \
+  pre##_eaxtagsz[] = { KSZ_RANGE, PRE##_BLKSZ, 0, PRE##_BLKSZ, 1 };    \
+                                                                       \
+/* --- @pre_eaxsetkey@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_eaxkey *key@ = pointer to key block to fill in     \
+ *             @const void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an EAX key block.                           \
+ */                                                                    \
+                                                                       \
+void pre##_eaxsetkey(pre##_eaxkey *key, const void *k, size_t ksz)     \
+{                                                                      \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+                                                                       \
+  /* Initialize the block cipher. */                                   \
+  pre##_init(&key->ctx, k, ksz);                                       \
+                                                                       \
+  /* Set up the OMAC masks. */                                         \
+  pre##_omacmasks(&key->ctx, key->m0, key->m1);                                \
+                                                                       \
+  /* Set up the OMAC tweaks.  EAX tweaks its MAC by simply stitching   \
+   * magic block-wide prefixes %$t_0$%, %$t_1$%, %$t_2$% (which are    \
+   * simply the numbers 0, 1, 2) on the front of strings.  We can      \
+   * accelerate things by caching two values for each tweak:           \
+   *                                                                   \
+   *   * %$v_i = E_K(t_i)$% is the accumulator that results from       \
+   *    pushing the tweak through the blockcipher, which we'd          \
+   *    calculate if the original message was nonempty.                \
+   *                                                                   \
+   *   * %$z_i = E_K(t_0 \xor m_0)$% is the tweak with the `full final \
+   *    buffer' mask applied, which is the final tag for a final empty \
+   *    message. \
+   */                                                                  \
+  BLKC_BSET(PRE, t, 0); pre##_eblk(&key->ctx, t, key->v0);             \
+  BLKC_XMOVE(PRE, t, key->m0); pre##_eblk(&key->ctx, t, key->z0);      \
+  BLKC_BSET(PRE, t, 1); pre##_eblk(&key->ctx, t, key->v1);             \
+  BLKC_XMOVE(PRE, t, key->m0); pre##_eblk(&key->ctx, t, key->z1);      \
+  BLKC_BSET(PRE, t, 2); pre##_eblk(&key->ctx, t, key->v2);             \
+  BLKC_XMOVE(PRE, t, key->m0); pre##_eblk(&key->ctx, t, key->z2);      \
+}                                                                      \
+                                                                       \
+/* --- @pre_eaxaadinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxaadctx *aad@ = pointer to AAD context           \
+ *             @const pre_eaxkey *key@ = pointer to key block          \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an EAX AAD (`additional authenticated       \
+ *             data') context associated with a given key.  AAD        \
+ *             contexts can be copied and/or reused, saving time if    \
+ *             the AAD for a number of messages has a common prefix.   \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around, though        \
+ *             usually there'll at least be another copy in some EAX   \
+ *             operation context because the AAD on its own isn't much \
+ *             good.                                                   \
+ */                                                                    \
+                                                                       \
+void pre##_eaxaadinit(pre##_eaxaadctx *aad, const pre##_eaxkey *key)   \
+  { aad->k = *key; aad->off = 0; BLKC_MOVE(PRE, aad->a, key->v1); }    \
+                                                                       \
+/* --- @pre_eaxaadhash@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxaadctx *aad@ = pointer to AAD context           \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.                             \
+ */                                                                    \
+                                                                       \
+void pre##_eaxaadhash(pre##_eaxaadctx *aad, const void *p, size_t sz)  \
+{                                                                      \
+  rsvr_state st;                                                       \
+  const octet *q;                                                      \
+                                                                       \
+  rsvr_setup(&st, &pre##_omacpolicy, aad->b, &aad->off, p, sz);                \
+  RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0)          \
+    OMAC_BLOCK(PRE, pre, &aad->k.ctx, aad->a, q);                      \
+}                                                                      \
+                                                                       \
+/* --- @pre_eaxinit@ --- *                                             \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX context              \
+ *             @const pre_eaxkey *key@ = pointer to key block          \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initialize an EAX operation context with a given key.   \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+void pre##_eaxinit(pre##_eaxctx *ctx, const pre##_eaxkey *k,           \
+                  const void *n, size_t nsz)                           \
+  { ctx->k = *k; pre##_eaxreinit(ctx, n, nsz); }                       \
+                                                                       \
+/* --- @pre_eaxreinit@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX context              \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Reinitialize an EAX operation context, changing the     \
+ *             nonce.                                                  \
+ */                                                                    \
+                                                                       \
+void pre##_eaxreinit(pre##_eaxctx *ctx, const void *n, size_t nsz)     \
+{                                                                      \
+  octet b[PRE##_BLKSZ];                                                        \
+  const octet *q = n;                                                  \
+                                                                       \
+  /* Initialize the OMAC context with the right tweak. */              \
+  BLKC_MOVE(PRE, ctx->a, ctx->k.v2);                                   \
+  ctx->off = 0;                                                                \
+                                                                       \
+  /* Calculate the initial counter from the nonce.  This is OMAC again,        \
+   * but this time we know that we're starting from a clean slate and  \
+   * we have the whole input in one go, so we don't bother with the    \
+   * full reservoir machinery.                                         \
+   */                                                                  \
+  if (!nsz)                                                            \
+    BLKC_MOVE(PRE, ctx->c0, ctx->k.z0);                                        \
+  else {                                                               \
+    BLKC_MOVE(PRE, ctx->c0, ctx->k.v0);                                        \
+    while (nsz > PRE##_BLKSZ) {                                                \
+      OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->c0, q);                   \
+      q += PRE##_BLKSZ; nsz -= PRE##_BLKSZ;                            \
+    }                                                                  \
+    memcpy(b, q, nsz);                                                 \
+    pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1,                  \
+                  ctx->c0, b, nsz);                                    \
+  }                                                                    \
+                                                                       \
+  /* We must remember the initial counter for the final tag            \
+   * calculation.  (I conjecture that storing the final counter instead        \
+   * would be just as secure, and require less state, but I've not     \
+   * proven this, and anyway it wouldn't interoperate.)  Copy it to    \
+   * make the working counter.                                         \
+   */                                                                  \
+  BLKC_MOVE(PRE, ctx->c, ctx->c0);                                     \
+}                                                                      \
+                                                                       \
+/* --- @pre_eaxencrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX operation context    \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For EAX, we always write a ciphertext chunk the same    \
+ *             size as the plaintext.  The messing about with @buf@    \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+int pre##_eaxencrypt(pre##_eaxctx *ctx,                                        \
+                    const void *src, size_t sz, buf *dst)              \
+{                                                                      \
+  rsvr_plan plan;                                                      \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *p = src;                                                        \
+  octet *q, *r, y;                                                     \
+                                                                       \
+  /* Allocate space for the ciphertext. */                             \
+  if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+                                                                       \
+  /* Determine the buffering plan.  Our buffer is going to do double-  \
+   * duty here.  The end portion is going to contain mask from the     \
+   * encrypted counter which we mix into the plaintext to encrypt it;  \
+   * the start portion, which originally mask bytes we've already used,        \
+   * will hold the output ciphertext, which will eventually be         \
+   * collected into the OMAC state.                                    \
+   */                                                                  \
+  rsvr_mkplan(&plan, &pre##_omacpolicy, ctx->off, sz);                 \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the buffer is     \
+   * empty, then that means that we haven't yet encrypted the current  \
+   * counter, so we should do that and advance it.                     \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c);     \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
+    }                                                                  \
+    r = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    while (plan.head--) { y = *p++ ^ *r; *r++ = *q++ = y; }            \
+  }                                                                    \
+                                                                       \
+  /* If we've filled up the buffer then we need to cycle the MAC and   \
+   * reset the offset.                                                 \
+   */                                                                  \
+  if (plan.from_rsvr) {                                                        \
+    OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->a, ctx->b);                 \
+    ctx->off = 0;                                                      \
+  }                                                                    \
+                                                                       \
+  /* Now to process the main body of the input.  We sneakily open-code \
+   * the OMAC part of this.                                            \
+   */                                                                  \
+  while (plan.from_input) {                                            \
+    pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c);       \
+    BLKC_XLOAD(PRE, t, p); p += PRE##_BLKSZ;                           \
+    BLKC_STORE(PRE, q, t); q += PRE##_BLKSZ;                           \
+    BLKC_XMOVE(PRE, ctx->a, t); pre##_eblk(&ctx->k.ctx, ctx->a, ctx->a); \
+    plan.from_input -= PRE##_BLKSZ;                                    \
+  }                                                                    \
+                                                                       \
+  /* Finally, deal with any final portion.  If there is one, we know   \
+   * that the buffer is empty: we must have filled it above, or this   \
+   * would all count as `initial' data.                                        \
+   */                                                                  \
+  if (plan.tail) {                                                     \
+    pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c);       \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    r = ctx->b; ctx->off += plan.tail;                                 \
+    while (plan.tail--) { y = *p++ ^ *r; *r++ = *q++ = y; }            \
+  }                                                                    \
+                                                                       \
+  /* And we're done. */                                                        \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_eaxdecrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX operation context    \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For EAX, we always write a plaintext chunk the same     \
+ *             size as the ciphertext.  The messing about with @buf@   \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+int pre##_eaxdecrypt(pre##_eaxctx *ctx,                                        \
+                    const void *src, size_t sz, buf *dst)              \
+{                                                                      \
+  rsvr_plan plan;                                                      \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ];                             \
+  const octet *p = src;                                                        \
+  octet *q, *r, y;                                                     \
+                                                                       \
+  /* Allocate space for the plaintext. */                              \
+  if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+                                                                       \
+  /* Determine the buffering plan.  Our buffer is going to do double-  \
+   * duty here.  The end portion is going to contain mask from the     \
+   * encrypted counter which we mix into the plaintext to encrypt it;  \
+   * the start portion, which originally mask bytes we've already used,        \
+   * will hold the input ciphertext, which will eventually be          \
+   * collected into the OMAC state.                                    \
+   */                                                                  \
+  rsvr_mkplan(&plan, &pre##_omacpolicy, ctx->off, sz);                 \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the buffer is     \
+   * empty, then that means that we haven't yet encrypted the current  \
+   * counter, so we should do that and advance it.                     \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c);     \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
+    }                                                                  \
+    r = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    while (plan.head--) { y = *p++; *q++ = y ^ *r; *r++ = y; }         \
+  }                                                                    \
+                                                                       \
+  /* If we've filled up the buffer then we need to cycle the MAC and   \
+   * reset the offset.                                                 \
+   */                                                                  \
+  if (plan.from_rsvr) {                                                        \
+    OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->a, ctx->b);                 \
+    ctx->off = 0;                                                      \
+  }                                                                    \
+                                                                       \
+  /* Now to process the main body of the input.  We sneakily open-code \
+   * the OMAC part of this.                                            \
+   */                                                                  \
+  while (plan.from_input) {                                            \
+    pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c);       \
+    BLKC_LOAD(PRE, u, p); p += PRE##_BLKSZ;                            \
+    BLKC_XSTORE(PRE, q, t, u); q += PRE##_BLKSZ;                       \
+    BLKC_XMOVE(PRE, ctx->a, u); pre##_eblk(&ctx->k.ctx, ctx->a, ctx->a); \
+    plan.from_input -= PRE##_BLKSZ;                                    \
+  }                                                                    \
+                                                                       \
+  /* Finally, deal with any final portion.  If there is one, we know   \
+   * that the buffer is empty: we must have filled it above, or this   \
+   * would all count as `initial' data.                                        \
+   */                                                                  \
+  if (plan.tail) {                                                     \
+    pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c);       \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    r = ctx->b; ctx->off += plan.tail;                                 \
+    while (plan.tail--) { y = *p++; *q++ = y ^ *r; *r++ = y; }         \
+  }                                                                    \
+                                                                       \
+  /* And we're done. */                                                        \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_eaxtag@ --- *                                              \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to an EAX context           \
+ *             @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @octet *t@ = where to write a (full-length) tag         \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes an EAX operation, by calculating the tag.      \
+ */                                                                    \
+                                                                       \
+static void pre##_eaxtag(pre##_eaxctx *ctx,                            \
+                        const pre##_eaxaadctx *aad, octet *t)          \
+{                                                                      \
+  octet b[PRE##_BLKSZ];                                                        \
+  uint32 u[PRE##_BLKSZ/4];                                             \
+                                                                       \
+  /* Finish tagging the ciphertext.  (The buffer is empty if and only  \
+   * if there was no message, since the OMAC reservoir policy leaves   \
+   * the buffer full.)                                                 \
+   */                                                                  \
+  if (!ctx->off) BLKC_MOVE(PRE, ctx->a, ctx->k.z2);                    \
+  else pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1,               \
+                     ctx->a, ctx->b, ctx->off);                        \
+                                                                       \
+  /* If there's no AAD, because the pointer is null or no data was     \
+   * supplied, then use the cached empty-header tag.  Otherwise                \
+   * calculate the tag for the AAD.  Either way, mix the result into   \
+   * ctx->A, and be careful not to modify the AAD context.  (Again, the        \
+   * buffer is empty if and only if there was no AAD.)                 \
+   */                                                                  \
+  if (!aad || !aad->off) BLKC_XMOVE(PRE, ctx->a, ctx->k.z1);           \
+  else {                                                               \
+    BLKC_MOVE(PRE, u, aad->a); memcpy(b, aad->b, aad->off);            \
+    pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1, u, b, aad->off); \
+    BLKC_XMOVE(PRE, ctx->a, u);                                                \
+  }                                                                    \
+                                                                       \
+  /* Finally, mix in the initial counter value. */                     \
+  BLKC_XMOVE(PRE, ctx->a, ctx->c0);                                    \
+                                                                       \
+  /* We're done. */                                                    \
+  BLKC_STORE(PRE, t, ctx->a);                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_eaxencryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to an EAX context           \
+ *             @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an EAX encryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  EAX doesn't buffer ciphertext, but \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+int pre##_eaxencryptdone(pre##_eaxctx *ctx,                            \
+                        const pre##_eaxaadctx *aad, buf *dst,          \
+                        void *tag, size_t tsz)                         \
+{                                                                      \
+  octet t[PRE##_BLKSZ];                                                        \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  if (!BOK(dst)) return (-1);                                          \
+  pre##_eaxtag(ctx, aad, t); memcpy(tag, t, tsz);                      \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_eaxdecryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to an EAX context           \
+ *             @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an EAX decryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  EAX doesn't buffer plaintext, but  \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+int pre##_eaxdecryptdone(pre##_eaxctx *ctx,                            \
+                        const pre##_eaxaadctx *aad, buf *dst,          \
+                        const void *tag, size_t tsz)                   \
+{                                                                      \
+  octet t[PRE##_BLKSZ];                                                        \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  if (!BOK(dst)) return (-1);                                          \
+  pre##_eaxtag(ctx, aad, t);                                           \
+  if (!ct_memeq(tag, t, tsz)) return (0);                              \
+  else return (+1);                                                    \
+}                                                                      \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+typedef struct gactx {                                                 \
+  gaead_aad a;                                                         \
+  pre##_eaxaadctx aad;                                                 \
+} gactx;                                                               \
+                                                                       \
+                                                                       \
+static gaead_aad *gadup(const gaead_aad *a)                            \
+  { gactx *aad = S_CREATE(gactx); *aad = *(gactx *)a; return (&aad->a); } \
+                                                                       \
+static void gahash(gaead_aad *a, const void *h, size_t hsz)            \
+  { gactx *aad = (gactx *)a; pre##_eaxaadhash(&aad->aad, h, hsz); }    \
+                                                                       \
+static void gadestroy(gaead_aad *a)                                    \
+  { gactx *aad = (gactx *)a; BURN(*aad); S_DESTROY(aad); }             \
+                                                                       \
+static const gaead_aadops gaops =                                      \
+  { &pre##_eax, gadup, gahash, gadestroy };                            \
+                                                                       \
+static gaead_aad *gaad(const pre##_eaxkey *k)                          \
+{                                                                      \
+  gactx *aad = S_CREATE(gactx);                                                \
+  aad->a.ops = &gaops;                                                 \
+  pre##_eaxaadinit(&aad->aad, k);                                      \
+  return (&aad->a);                                                    \
+}                                                                      \
+                                                                       \
+typedef struct gectx {                                                 \
+  gaead_enc e;                                                         \
+  pre##_eaxctx ctx;                                                    \
+} gectx;                                                               \
+                                                                       \
+static gaead_aad *geaad(gaead_enc *e)                                  \
+  { gectx *enc = (gectx *)e; return (gaad(&enc->ctx.k)); }             \
+                                                                       \
+static int gereinit(gaead_enc *e, const void *n, size_t nsz,           \
+                   size_t hsz, size_t msz, size_t tsz)                 \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  pre##_eaxreinit(&enc->ctx, n, nsz);                                  \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int geenc(gaead_enc *e, const void *m, size_t msz, buf *b)      \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_eaxencrypt(&enc->ctx, m, msz, b));                     \
+}                                                                      \
+                                                                       \
+static int gedone(gaead_enc *e, const gaead_aad *a,                    \
+                 buf *b, void *t, size_t tsz)                          \
+{                                                                      \
+  gectx *enc = (gectx *)e; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_eaxencryptdone(&enc->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gedestroy(gaead_enc *e)                                    \
+  { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); }             \
+                                                                       \
+static const gaead_encops geops =                                      \
+  { &pre##_eax, geaad, gereinit, geenc, gedone, gedestroy };           \
+                                                                       \
+typedef struct gdctx {                                                 \
+  gaead_dec d;                                                         \
+  pre##_eaxctx ctx;                                                    \
+} gdctx;                                                               \
+                                                                       \
+static gaead_aad *gdaad(gaead_dec *d)                                  \
+  { gdctx *dec = (gdctx *)d; return (gaad(&dec->ctx.k)); }             \
+                                                                       \
+static int gdreinit(gaead_dec *d, const void *n, size_t nsz,           \
+                   size_t hsz, size_t csz, size_t tsz)                 \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  pre##_eaxreinit(&dec->ctx, n, nsz);                                  \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int gddec(gaead_dec *d, const void *c, size_t csz, buf *b)      \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_eaxdecrypt(&dec->ctx, c, csz, b));                     \
+}                                                                      \
+                                                                       \
+static int gddone(gaead_dec *d, const gaead_aad *a,                    \
+                 buf *b, const void *t, size_t tsz)                    \
+{                                                                      \
+  gdctx *dec = (gdctx *)d; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_eaxdecryptdone(&dec->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gddestroy(gaead_dec *d)                                    \
+  { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); }             \
+                                                                       \
+static const gaead_decops gdops =                                      \
+  { &pre##_eax, gdaad, gdreinit, gddec, gddone, gddestroy };           \
+                                                                       \
+typedef struct gkctx {                                                 \
+  gaead_key k;                                                         \
+  pre##_eaxkey key;                                                    \
+} gkctx;                                                               \
+                                                                       \
+static gaead_aad *gkaad(const gaead_key *k)                            \
+  { gkctx *key = (gkctx *)k; return (gaad(&key->key)); }               \
+                                                                       \
+static gaead_enc *gkenc(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t msz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gectx *enc;                                                          \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (0);                                   \
+  enc = S_CREATE(gectx); enc->e.ops = &geops;                          \
+  pre##_eaxinit(&enc->ctx, &key->key, n, nsz);                         \
+  return (&enc->e);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_dec *gkdec(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t csz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gdctx *dec;                                                          \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (0);                                   \
+  dec = S_CREATE(gdctx); dec->d.ops = &gdops;                          \
+  pre##_eaxinit(&dec->ctx, &key->key, n, nsz);                         \
+  return (&dec->d);                                                    \
+}                                                                      \
+                                                                       \
+static void gkdestroy(gaead_key *k)                                    \
+  { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); }             \
+                                                                       \
+static const gaead_keyops gkops =                                      \
+  { &pre##_eax, gkaad, gkenc, gkdec, gkdestroy };                      \
+                                                                       \
+static gaead_key *gckey(const void *k, size_t ksz)                     \
+{                                                                      \
+  gkctx *key = S_CREATE(gkctx);                                                \
+  key->k.ops = &gkops;                                                 \
+  pre##_eaxsetkey(&key->key, k, ksz);                                  \
+  return (&key->k);                                                    \
+}                                                                      \
+                                                                       \
+const gcaead pre##_eax = {                                             \
+  name "-eax",                                                         \
+  pre##_keysz, pre##_eaxnoncesz, pre##_eaxtagsz,                       \
+  PRE##_BLKSZ, 0, 0, 0,                                                        \
+  gckey                                                                        \
+};                                                                     \
+                                                                       \
+EAX_TESTX(PRE, pre, name, fname)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#define EAX_TEST(PRE, pre) EAX_TESTX(PRE, pre, #pre, #pre)
+
+/* --- @EAX_TEST@ --- *
+ *
+ * Arguments:  @PRE, pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Standard test rig for EAX functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define EAX_TESTX(PRE, pre, name, fname)                               \
+                                                                       \
+static int eaxverify(dstr *v)                                          \
+{                                                                      \
+  pre##_eaxkey key;                                                    \
+  pre##_eaxaadctx aad;                                                 \
+  pre##_eaxctx ctx;                                                    \
+  int ok = 1, win;                                                     \
+  int i;                                                               \
+  octet *p;                                                            \
+  int szs[] = { 1, 7, 192, -1, 0 }, *ip;                               \
+  size_t hsz, msz;                                                     \
+  dstr d = DSTR_INIT, t = DSTR_INIT;                                   \
+  buf b;                                                               \
+                                                                       \
+  dstr_ensure(&d, v[4].len > v[3].len ? v[4].len : v[3].len);          \
+  dstr_ensure(&t, v[5].len); t.len = v[5].len;                         \
+                                                                       \
+  pre##_eaxsetkey(&key, v[0].buf, v[0].len);                           \
+                                                                       \
+  for (ip = szs; *ip; ip++) {                                          \
+                                                                       \
+    pre##_eaxinit(&ctx, &key, (octet *)v[1].buf, v[1].len);            \
+                                                                       \
+    i = *ip;                                                           \
+    hsz = v[2].len;                                                    \
+    if (i == -1) i = hsz;                                              \
+    if (i > hsz) continue;                                             \
+    p = (octet *)v[2].buf;                                             \
+    pre##_eaxaadinit(&aad, &key);                                      \
+    while (hsz) {                                                      \
+      if (i > hsz) i = hsz;                                            \
+      pre##_eaxaadhash(&aad, p, i);                                    \
+      p += i; hsz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[3].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[3].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_eaxencrypt(&ctx, p, i, &b)) {                          \
+       puts("!! eaxencrypt reports failure");                          \
+       goto fail_enc;                                                  \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    if (pre##_eaxencryptdone(&ctx, &aad, &b, (octet *)t.buf, t.len)) { \
+      puts("!! eaxencryptdone reports failure");                       \
+      goto fail_enc;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[4].len ||                                           \
+       memcmp(d.buf, v[4].buf, v[4].len) != 0 ||                       \
+       memcmp(t.buf, v[5].buf, v[5].len) != 0) {                       \
+    fail_enc:                                                          \
+      printf("\nfail encrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tmessage = ", stdout); type_hex.dump(&v[3], stdout);   \
+      fputs("\n\texp ct = ", stdout); type_hex.dump(&v[4], stdout);    \
+      fputs("\n\tcalc ct = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\texp tag = ", stdout); type_hex.dump(&v[5], stdout);   \
+      fputs("\n\tcalc tag = ", stdout); type_hex.dump(&t, stdout);     \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+                                                                       \
+    pre##_eaxinit(&ctx, &key, (octet *)v[1].buf, v[1].len);            \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[4].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[4].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_eaxdecrypt(&ctx, p, i, &b)) {                          \
+       puts("!! eaxdecrypt reports failure");                          \
+       win = 0; goto fail_dec;                                         \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    win = pre##_eaxdecryptdone(&ctx, &aad, &b,                         \
+                              (octet *)v[5].buf, v[5].len);            \
+    if (win < 0) {                                                     \
+      puts("!! eaxdecryptdone reports failure");                       \
+      goto fail_dec;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[3].len || !win ||                                   \
+       memcmp(d.buf, v[3].buf, v[3].len) != 0) {                       \
+    fail_dec:                                                          \
+      printf("\nfail decrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tciphertext = ", stdout); type_hex.dump(&v[4], stdout);        \
+      fputs("\n\texp pt = ", stdout); type_hex.dump(&v[3], stdout);    \
+      fputs("\n\tcalc pt = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\ttag = ", stdout); type_hex.dump(&v[5], stdout);       \
+      printf("\n\tverify %s", win ? "ok" : "FAILED");                  \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  dstr_destroy(&d); dstr_destroy(&t);                                  \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static test_chunk aeaddefs[] = {                                       \
+  { name "-eax", eaxverify,                                            \
+    { &type_hex, &type_hex, &type_hex, &type_hex,                      \
+      &type_hex, &type_hex, 0 } },                                     \
+  { 0, 0, { 0 } }                                                      \
+};                                                                     \
+                                                                       \
+int main(int argc, char *argv[])                                       \
+{                                                                      \
+  ego(argv[0]);                                                                \
+  test_run(argc, argv, aeaddefs, SRCDIR"/t/" fname);                   \
+  return (0);                                                          \
+}
+
+#else
+#  define EAX_TESTX(PRE, pre, name, fname)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/eax.h b/symm/eax.h
new file mode 100644 (file)
index 0000000..0018da6
--- /dev/null
@@ -0,0 +1,294 @@
+/* -*-c-*-
+ *
+ * The EAX authenticated-encryption mode
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Notes on EAX ------------------------------------------------------*
+ *
+ * The name doesn't appear to be short for anything convincing.  EAX was
+ * designed in 2004 by Mihir Bellare, Phillip Rogaway, and David Wagner, as a
+ * response to CCM's deficiencies, which Rogaway and Wagner had complained
+ * about the previous year.  Like CCM, it's a patent-free authenticated
+ * encryption scheme based on counter mode and CBC-MAC, and needs two
+ * blockcipher applications per message block, but it's much more refined
+ * than CCM.  The EAX specification is clear about how the mode applies to
+ * arbitrary block sizes, and I've not had to make any decisions on how to
+ * extend it myself.
+ *
+ * EAX allows arbitrarily sized nonces, and doesn't require precommitment to
+ * any lengths, and allows header data to be processed independently of any
+ * message.  It's basically about as good as a rate-1/2 scheme is going to
+ * be.
+ */
+
+#ifndef CATACOMB_EAX_H
+#define CATACOMB_EAX_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @EAX_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates declarations for EAX authenticated-encryption mode.
+ */
+
+#define EAX_DECL(PRE, pre)                                             \
+                                                                       \
+typedef struct pre##_eaxkey {                                          \
+  pre##_ctx ctx;                       /* Block cipher key */          \
+  uint32 m0[PRE##_BLKSZ/4], m1[PRE##_BLKSZ/4]; /* Final OMAC masks */  \
+  uint32 v0[PRE##_BLKSZ/4],            /* OMAC tweak accumulators */   \
+    v1[PRE##_BLKSZ/4], v2[PRE##_BLKSZ/4];                              \
+  uint32 z0[PRE##_BLKSZ/4],            /* Empty-message tag values */  \
+    z1[PRE##_BLKSZ/4], z2[PRE##_BLKSZ/4];                              \
+} pre##_eaxkey;                                                                \
+                                                                       \
+typedef struct pre##_eaxaadctx {                                       \
+  pre##_eaxkey k;                      /* Underlying key */            \
+  uint32 a[PRE##_BLKSZ/4];             /* OMAC accumulator */          \
+  octet b[PRE##_BLKSZ];                        /* Input buffer */              \
+  unsigned off;                                /* Length of stuff in buffer */ \
+} pre##_eaxaadctx;                                                     \
+                                                                       \
+typedef struct pre##_eaxctx {                                          \
+  /* The buffer is split into two portions.  The first N octets hold a \
+   * chunk of ciphertext, which will be fed into the OMAC calculation; \
+   * the remaining BLKSZ - N octets hold E_K(C), which is the XOR mask \
+   * to apply to the plaintext or ciphertext.                          \
+   */                                                                  \
+  pre##_eaxkey k;                      /* Underlying key */            \
+  uint32 c[PRE##_BLKSZ/4];             /* Current counter value */     \
+  uint32 c0[PRE##_BLKSZ/4];            /* Initial counter */           \
+  uint32 a[PRE##_BLKSZ];               /* OMAC accumulator */          \
+  octet b[PRE##_BLKSZ];                        /* Ciphertext/mask buffer */    \
+  unsigned off;                                /* Crossover point in buffer */ \
+} pre##_eaxctx;                                                                \
+                                                                       \
+extern const octet pre##_eaxnoncesz[], pre##_eaxtagsz[];               \
+                                                                       \
+/* --- @pre_eaxsetkey@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_eaxkey *key@ = pointer to key block to fill in     \
+ *             @const void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an EAX key block.                           \
+ */                                                                    \
+                                                                       \
+extern void pre##_eaxsetkey(pre##_eaxkey */*key*/,                     \
+                           const void */*k*/, size_t /*ksz*/);         \
+                                                                       \
+/* --- @pre_eaxaadinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxaadctx *aad@ = pointer to AAD context           \
+ *             @const pre_eaxkey *key@ = pointer to key block          \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an EAX AAD (`additional authenticated       \
+ *             data') context associated with a given key.  AAD        \
+ *             contexts can be copied and/or reused, saving time if    \
+ *             the AAD for a number of messages has a common prefix.   \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around, though        \
+ *             usually there'll at least be another copy in some EAX   \
+ *             operation context because the AAD on its own isn't much \
+ *             good.                                                   \
+ */                                                                    \
+                                                                       \
+extern void pre##_eaxaadinit(pre##_eaxaadctx */*aad*/,                 \
+                            const pre##_eaxkey */*key*/);              \
+                                                                       \
+/* --- @pre_eaxaadhash@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxaadctx *aad@ = pointer to AAD context           \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.                             \
+ */                                                                    \
+                                                                       \
+extern void pre##_eaxaadhash(pre##_eaxaadctx */*aad*/,                 \
+                            const void */*p*/, size_t /*sz*/);         \
+                                                                       \
+/* --- @pre_eaxinit@ --- *                                             \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX context              \
+ *             @const pre_eaxkey *key@ = pointer to key block          \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initialize an EAX operation context with a given key.   \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+extern void pre##_eaxinit(pre##_eaxctx */*ctx*/,                       \
+                         const pre##_eaxkey */*k*/,                    \
+                         const void */*n*/, size_t /*nsz*/);           \
+                                                                       \
+/* --- @pre_eaxreinit@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX context              \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Reinitialize an EAX operation context, changing the     \
+ *             nonce.                                                  \
+ */                                                                    \
+                                                                       \
+extern void pre##_eaxreinit(pre##_eaxctx */*ctx*/,                     \
+                           const void */*n*/, size_t /*nsz*/);         \
+                                                                       \
+/* --- @pre_eaxencrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX operation context    \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For EAX, we always write a ciphertext chunk the same    \
+ *             size as the plaintext.  The messing about with @buf@    \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+extern int pre##_eaxencrypt(pre##_eaxctx */*ctx*/,                     \
+                           const void */*src*/, size_t /*sz*/,         \
+                           buf */*dst*/);                              \
+                                                                       \
+/* --- @pre_eaxdecrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to EAX operation context    \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For EAX, we always write a plaintext chunk the same     \
+ *             size as the ciphertext.  The messing about with @buf@   \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+extern int pre##_eaxdecrypt(pre##_eaxctx */*ctx*/,                     \
+                           const void */*src*/, size_t /*sz*/,         \
+                           buf */*dst*/);                              \
+                                                                       \
+/* --- @pre_eaxencryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to an EAX context           \
+ *             @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an EAX encryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  EAX doesn't buffer ciphertext, but \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+extern int pre##_eaxencryptdone(pre##_eaxctx */*ctx*/,                 \
+                               const pre##_eaxaadctx */*aad*/,         \
+                               buf */*dst*/,                           \
+                               void */*tag*/, size_t /*tsz*/);         \
+                                                                       \
+/* --- @pre_eaxdecryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_eaxctx *ctx@ = pointer to an EAX context           \
+ *             @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an EAX decryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  EAX doesn't buffer plaintext, but  \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+extern int pre##_eaxdecryptdone(pre##_eaxctx */*ctx*/,                 \
+                               const pre##_eaxaadctx */*aad*/,         \
+                               buf */*dst*/,                           \
+                               const void */*tag*/, size_t /*tsz*/);   \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+extern const gcaead pre##_eax;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index 568ffa1..c69790d 100644 (file)
@@ -80,9 +80,7 @@
  */                                                                    \
                                                                        \
 void pre##_ecbsetkey(pre##_ecbctx *ctx, const pre##_ctx *k)            \
-{                                                                      \
-  ctx->ctx = *k;                                                       \
-}                                                                      \
+  { ctx->ctx = *k; }                                                   \
                                                                        \
 /* --- @pre_ecbinit@ --- *                                             \
  *                                                                     \
@@ -98,11 +96,9 @@ void pre##_ecbsetkey(pre##_ecbctx *ctx, const pre##_ctx *k)          \
  */                                                                    \
                                                                        \
 void pre##_ecbinit(pre##_ecbctx *ctx,                                  \
-                    const void *key, size_t sz,                        \
-                    const void *iv)                                    \
-{                                                                      \
-  pre##_init(&ctx->ctx, key, sz);                                      \
-}                                                                      \
+                  const void *key, size_t sz,                          \
+                  const void *iv)                                      \
+  { pre##_init(&ctx->ctx, key, sz); }                                  \
                                                                        \
 /* --- @pre_ecbencrypt@ --- *                                          \
  *                                                                     \
@@ -120,16 +116,19 @@ void pre##_ecbinit(pre##_ecbctx *ctx,                                     \
  */                                                                    \
                                                                        \
 void pre##_ecbencrypt(pre##_ecbctx *ctx,                               \
-                       const void *src, void *dest,                    \
-                       size_t sz)                                      \
+                     const void *src, void *dest,                      \
+                     size_t sz)                                        \
 {                                                                      \
   const octet *s = src;                                                        \
   octet *d = dest;                                                     \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  octet b[PRE##_BLKSZ];                                                        \
+  octet y;                                                             \
+  unsigned i;                                                          \
                                                                        \
-  /* --- Empty blocks are trivial --- */                               \
+  /* --- Empty blocks are trivial, and ECB is stateless --- */         \
                                                                        \
-  if (!sz)                                                             \
-    return;                                                            \
+  if (!sz || !d) return;                                               \
                                                                        \
   /* --- Short blocks aren't allowed in ECB --- *                      \
    *                                                                   \
@@ -146,19 +145,11 @@ void pre##_ecbencrypt(pre##_ecbctx *ctx,                          \
    * Hopefully...                                                      \
    */                                                                  \
                                                                        \
-  while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) {                 \
-    uint32 x[PRE##_BLKSZ / 4];                                         \
-    if (!s)                                                            \
-      BLKC_ZERO(PRE, x);                                               \
-    else {                                                             \
-      BLKC_LOAD(PRE, x, s);                                            \
-      s += PRE##_BLKSZ;                                                        \
-    }                                                                  \
-    pre##_eblk(&ctx->ctx, x, x);                                       \
-    if (d) {                                                           \
-      BLKC_STORE(PRE, d, x);                                           \
-      d += PRE##_BLKSZ;                                                        \
-    }                                                                  \
+  while (sz >= 2*PRE##_BLKSZ || sz == PRE##_BLKSZ) {                   \
+    if (!s) BLKC_ZERO(PRE, t);                                         \
+    else { BLKC_LOAD(PRE, t, s); s += PRE##_BLKSZ; }                   \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ;                           \
     sz -= PRE##_BLKSZ;                                                 \
   }                                                                    \
                                                                        \
@@ -168,9 +159,6 @@ void pre##_ecbencrypt(pre##_ecbctx *ctx,                            \
    */                                                                  \
                                                                        \
   if (sz) {                                                            \
-    uint32 x[PRE##_BLKSZ / 4];                                         \
-    octet b[PRE##_BLKSZ];                                              \
-    unsigned i;                                                                \
                                                                        \
     /* --- Let @sz@ be the size of the partial block --- */            \
                                                                        \
@@ -183,14 +171,10 @@ void pre##_ecbencrypt(pre##_ecbctx *ctx,                          \
      * out yet, because I've not read the partial plaintext block.     \
      */                                                                        \
                                                                        \
-    if (!s)                                                            \
-      BLKC_ZERO(PRE, x);                                               \
-    else {                                                             \
-      BLKC_LOAD(PRE, x, s);                                            \
-      s += PRE##_BLKSZ;                                                        \
-    }                                                                  \
-    pre##_eblk(&ctx->ctx, x, x);                                       \
-    BLKC_STORE(PRE, b, x);                                             \
+    if (!s) BLKC_ZERO(PRE, t);                                         \
+    else { BLKC_LOAD(PRE, t, s); s += PRE##_BLKSZ; }                   \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, b, t);                                             \
                                                                        \
     /* --- Second stage --- *                                          \
      *                                                                 \
@@ -199,15 +183,11 @@ void pre##_ecbencrypt(pre##_ecbctx *ctx,                          \
      * ciphertext block.                                               \
      */                                                                        \
                                                                        \
-    if (d) d += PRE##_BLKSZ;                                           \
-    for (i = 0; i < sz; i++) {                                         \
-      register octet y = b[i];                                         \
-      b[i] = s[i];                                                     \
-      if (d) d[i] = y;                                                 \
-    }                                                                  \
-    BLKC_LOAD(PRE, x, b);                                              \
-    pre##_eblk(&ctx->ctx, x, x);                                       \
-    if (d) BLKC_STORE(PRE, d - PRE##_BLKSZ, x);                                \
+    d += PRE##_BLKSZ;                                                  \
+    for (i = 0; i < sz; i++) { y = b[i]; b[i] = s[i]; d[i] = y; }      \
+    BLKC_LOAD(PRE, t, b);                                              \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, d - PRE##_BLKSZ, t);                               \
   }                                                                    \
                                                                        \
   /* --- Done --- */                                                   \
@@ -236,11 +216,14 @@ void pre##_ecbdecrypt(pre##_ecbctx *ctx,                          \
 {                                                                      \
   const octet *s = src;                                                        \
   octet *d = dest;                                                     \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  octet b[PRE##_BLKSZ];                                                        \
+  octet y;                                                             \
+  unsigned i;                                                          \
                                                                        \
   /* --- Empty blocks are trivial --- */                               \
                                                                        \
-  if (!sz)                                                             \
-    return;                                                            \
+  if (!sz) return;                                                     \
                                                                        \
   /* --- Short blocks aren't allowed in ECB --- *                      \
    *                                                                   \
@@ -256,13 +239,10 @@ void pre##_ecbdecrypt(pre##_ecbctx *ctx,                          \
    * Each block is just handed to the block cipher in turn.            \
    */                                                                  \
                                                                        \
-  while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) {                 \
-    uint32 x[PRE##_BLKSZ / 4];                                         \
-    BLKC_LOAD(PRE, x, s);                                              \
-    pre##_dblk(&ctx->ctx, x, x);                                       \
-    BLKC_STORE(PRE, d, x);                                             \
-    s += PRE##_BLKSZ;                                                  \
-    d += PRE##_BLKSZ;                                                  \
+  while (sz >= 2*PRE##_BLKSZ || sz == PRE##_BLKSZ) {                   \
+    BLKC_LOAD(PRE, t, s); s += PRE##_BLKSZ;                            \
+    pre##_dblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ;                           \
     sz -= PRE##_BLKSZ;                                                 \
   }                                                                    \
                                                                        \
@@ -272,9 +252,6 @@ void pre##_ecbdecrypt(pre##_ecbctx *ctx,                            \
    */                                                                  \
                                                                        \
   if (sz) {                                                            \
-    uint32 x[PRE##_BLKSZ / 4];                                         \
-    octet b[PRE##_BLKSZ];                                              \
-    unsigned i;                                                                \
                                                                        \
     /* --- Let @sz@ be the size of the partial block --- */            \
                                                                        \
@@ -286,9 +263,9 @@ void pre##_ecbdecrypt(pre##_ecbctx *ctx,                            \
      * is carried over for the next encryption operation.              \
      */                                                                        \
                                                                        \
-    BLKC_LOAD(PRE, x, s);                                              \
-    pre##_dblk(&ctx->ctx, x, x);                                       \
-    BLKC_STORE(PRE, b, x);                                             \
+    BLKC_LOAD(PRE, t, s);                                              \
+    pre##_dblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, b, t);                                             \
                                                                        \
     /* --- Second stage --- *                                          \
      *                                                                 \
@@ -299,14 +276,10 @@ void pre##_ecbdecrypt(pre##_ecbctx *ctx,                          \
                                                                        \
     s += PRE##_BLKSZ;                                                  \
     d += PRE##_BLKSZ;                                                  \
-    for (i = 0; i < sz; i++) {                                         \
-      register octet y = s[i];                                         \
-      d[i] = b[i];                                                     \
-      b[i] = y;                                                                \
-    }                                                                  \
-    BLKC_LOAD(PRE, x, b);                                              \
-    pre##_dblk(&ctx->ctx, x, x);                                       \
-    BLKC_STORE(PRE, d - PRE##_BLKSZ, x);                               \
+    for (i = 0; i < sz; i++) { y = s[i]; d[i] = b[i]; b[i] = y; }      \
+    BLKC_LOAD(PRE, t, b);                                              \
+    pre##_dblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, d - PRE##_BLKSZ, t);                               \
   }                                                                    \
                                                                        \
   /* --- Done --- */                                                   \
@@ -332,23 +305,13 @@ static gcipher *ginit(const void *k, size_t sz)                           \
 }                                                                      \
                                                                        \
 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_ecbencrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_ecbencrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdecrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_ecbdecrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_ecbdecrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdestroy(gcipher *c)                                       \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  BURN(*g);                                                            \
-  S_DESTROY(g);                                                                \
-}                                                                      \
+  { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }                     \
                                                                        \
 static const gcipher_ops gops = {                                      \
   &pre##_ecb,                                                          \
@@ -368,9 +331,7 @@ ECB_TESTX(PRE, pre, name, fname)
 
 #ifdef TEST_RIG
 
-#include <stdio.h>
-
-#include "daftstory.h"
+#include "modes-test.h"
 
 /* --- @ECB_TEST@ --- *
  *
@@ -381,85 +342,28 @@ ECB_TESTX(PRE, pre, name, fname)
 
 #define ECB_TESTX(PRE, pre, name, fname)                               \
                                                                        \
-/* --- Initial plaintext for the test --- */                           \
-                                                                       \
-static const octet text[] = TEXT;                                      \
+static pre##_ctx key;                                                  \
+static pre##_ecbctx ctx;                                               \
                                                                        \
-/* --- Key and IV to use --- */                                                \
+static void pre##_ecb_test_setup(const octet *k, size_t ksz)           \
+  { pre##_init(&key, k, ksz); pre##_ecbsetkey(&ctx, &key); }           \
                                                                        \
-static const octet key[] = KEY;                                                \
-static const octet iv[] = IV;                                          \
+static void pre##_ecb_test_reset(const octet *iv)                      \
+  { ; }                                                                        \
                                                                        \
-/* --- Buffers for encryption and decryption output --- */             \
+static void pre##_ecb_test_enc(const octet *s, octet *d, size_t sz)    \
+  { pre##_ecbencrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-static octet ct[sizeof(text)];                                         \
-static octet pt[sizeof(text)];                                         \
+static void pre##_ecb_test_dec(const octet *s, octet *d, size_t sz)    \
+  { pre##_ecbdecrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-static void hexdump(const octet *p, size_t sz, size_t off)             \
+int main(int argc, char *argv[])                                       \
 {                                                                      \
-  const octet *q = p + sz;                                             \
-  for (sz = 0; p < q; p++, sz++) {                                     \
-    printf("%02x", *p);                                                        \
-    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
-      putchar(':');                                                    \
-  }                                                                    \
-}                                                                      \
-                                                                       \
-int main(void)                                                         \
-{                                                                      \
-  size_t sz = 0, rest;                                                 \
-  pre##_ecbctx ctx;                                                    \
-  int status = 0;                                                      \
-  int done = 0;                                                                \
-                                                                       \
-  size_t keysz = PRE##_KEYSZ ?                                         \
-    PRE##_KEYSZ : strlen((const char *)key);                           \
-                                                                       \
-  fputs(name "-ecb: ", stdout);                                                \
-                                                                       \
-  pre##_ecbinit(&ctx, key, keysz, iv);                                 \
-                                                                       \
-  while (sz <= sizeof(text)) {                                         \
-    rest = sizeof(text) - sz;                                          \
-    if ((sz != 0 && sz < PRE##_BLKSZ) ||                               \
-       (rest != 0 && rest < PRE##_BLKSZ))                              \
-      goto next;                                                       \
-    memcpy(ct, text, sizeof(text));                                    \
-    pre##_ecbencrypt(&ctx, ct, ct, sz);                                        \
-    pre##_ecbencrypt(&ctx, ct + sz, ct + sz, rest);                    \
-    memcpy(pt, ct, sizeof(text));                                      \
-    pre##_ecbdecrypt(&ctx, pt, pt, sz);                                        \
-    pre##_ecbdecrypt(&ctx, pt + sz, pt + sz, rest);                    \
-    if (memcmp(pt, text, sizeof(text)) == 0) {                         \
-      done++;                                                          \
-      if (sizeof(text) < 40 || done % 8 == 0)                          \
-       fputc('.', stdout);                                             \
-      if (done % 480 == 0)                                             \
-       fputs("\n\t", stdout);                                          \
-      fflush(stdout);                                                  \
-    } else {                                                           \
-      printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
-      status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
-       printf(", "); hexdump(text + sz, rest, sz);                     \
-       fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
-       printf(", "); hexdump(ct + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
-       printf(", "); hexdump(pt + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      fputc('\n', stdout);                                             \
-    }                                                                  \
-  next:                                                                        \
-    if (sz < 63)                                                       \
-      sz++;                                                            \
-    else                                                               \
-      sz += 9;                                                         \
-  }                                                                    \
-                                                                       \
-  fputs(status ? " failed\n" : " ok\n", stdout);                       \
-  return (status);                                                     \
+  return test_encmode(fname "-ecb", PRE##_KEYSZ, PRE##_BLKSZ,          \
+                     PRE##_BLKSZ, TEMF_REFALIGN,                       \
+                     pre##_ecb_test_setup, pre##_ecb_test_reset,       \
+                     pre##_ecb_test_enc, pre##_ecb_test_dec,           \
+                     argc, argv);                                      \
 }
 
 #else
diff --git a/symm/gaead.c b/symm/gaead.c
new file mode 100644 (file)
index 0000000..45aeb61
--- /dev/null
@@ -0,0 +1,123 @@
+/* -*-c-*-
+ *
+ * Generic authenticated encryption interface
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "gaead.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @gaead_encrypt@ --- *
+ *
+ * Arguments:  @const gaead_key *k@ = the AEAD key, already prepared
+ *             @const void *n@, @size_t nsz@ = nonce
+ *             @const void *h@, @size_t hsz@ = additional `header' data
+ *             @const void *m@, @size_t msz@ = message input
+ *             @void *c@, @size_t *csz_input@ = ciphertext output
+ *             @void *t@, @size_t tsz@ = tag output
+ *
+ * Returns:    Zero on success, @-1@ if the output buffer is too small.
+ *
+ * Use:                Encrypts and authenticates a message in a single operation.
+ *             This just saves a bunch of messing about with the various
+ *             @gaead_...@ objects.
+ *
+ *             On entry, @*csz_inout@ should be the capacity of the
+ *             ciphertext buffer; on exit, it will be updated with the
+ *             actual size of ciphertext produced.  The function will not
+ *             fail if @*csz_inout >= msz + k->c->ohd@.
+ */
+
+int gaead_encrypt(const gaead_key *k, const void *n, size_t nsz,
+                 const void *h, size_t hsz,
+                 const void *m, size_t msz,
+                 void *c, size_t *csz_inout,
+                 void *t, size_t tsz)
+{
+  gaead_enc *e = 0;
+  gaead_aad *a = 0;
+  buf b;
+  int rc;
+
+  buf_init(&b, c, *csz_inout);
+  e = GAEAD_ENC(k, n, nsz, hsz, msz, tsz); if (!e) { rc = -1; goto end; }
+  if (hsz) { a = GAEAD_AAD(e); GAEAD_HASH(a, h, hsz); }
+  rc = GAEAD_ENCRYPT(e, m, msz, &b); if (rc) goto end;
+  rc = GAEAD_DONE(e, a, &b, t, tsz);
+end:
+  if (rc >= 0) *csz_inout = BLEN(&b);
+  if (e) GAEAD_DESTROY(e);
+  if (a) GAEAD_DESTROY(a);
+  return (rc);
+}
+
+/* --- @gaead_decrypt@ --- *
+ *
+ * Arguments:  @const gaead_key *k@ = the AEAD key, already prepared
+ *             @const void *n@, @size_t nsz@ = nonce
+ *             @const void *h@, @size_t hsz@ = additional `header' data
+ *             @const void *c@, @size_t csz@ = ciphertext input
+ *             @void *m@, @size_t *msz_inout@ = message output
+ *             @const void *t@, @size_t tsz@ = tag input
+ *
+ * Returns:    @+1@ if everything is good; zero for authentication failure,
+ *             @-1@ for other problems.
+ *
+ * Use:                Decrypts and verifies a message in a single operation.
+ *             This just saves a bunch of messing about with the various
+ *             @gaead_...@ objects.
+ *
+ *             On entry, @*msz_inout@ should be the capacity of the
+ *             message buffer; on exit, it will be updated with the
+ *             actual size of message produced.  The function will not
+ *             fail if @*msz_inout >= csz@.
+ */
+
+int gaead_decrypt(const gaead_key *k, const void *n, size_t nsz,
+                 const void *h, size_t hsz,
+                 const void *c, size_t csz,
+                 void *m, size_t *msz_inout,
+                 const void *t, size_t tsz)
+{
+  gaead_dec *d = 0;
+  gaead_aad *a = 0;
+  buf b;
+  int rc;
+
+  buf_init(&b, m, *msz_inout);
+  d = GAEAD_DEC(k, n, nsz, hsz, csz, tsz); if (!d) { rc = -1; goto end; }
+  if (hsz) { a = GAEAD_AAD(d); GAEAD_HASH(a, h, hsz); }
+  rc = GAEAD_DECRYPT(d, c, csz, &b); if (rc) goto end;
+  rc = GAEAD_DONE(d, a, &b, t, tsz);
+end:
+  if (rc >= 0) *msz_inout = BLEN(&b);
+  if (d) GAEAD_DESTROY(d);
+  if (a) GAEAD_DESTROY(a);
+  return (rc);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/symm/gaead.h b/symm/gaead.h
new file mode 100644 (file)
index 0000000..33feb36
--- /dev/null
@@ -0,0 +1,394 @@
+/* -*-c-*-
+ *
+ * Generic authenticated encryption interface
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_GAEAD_H
+#define CATACOMB_GAEAD_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_BUF_H
+#  include "buf.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+#  include "keysz.h"
+#endif
+
+/*----- Generic AEAD interface --------------------------------------------*/
+
+typedef struct gaead_key {
+  const struct gaead_keyops *ops;
+} gaead_key;
+
+typedef struct gaead_enc {
+  const struct gaead_encops *ops;
+} gaead_enc;
+
+typedef struct gaead_dec {
+  const struct gaead_decops *ops;
+} gaead_dec;
+
+typedef struct gaead_aad {
+  const struct gaead_aadops *ops;
+} gaead_aad;
+
+typedef struct gaead_keyops {
+  const struct gcaead *c;              /* Pointer to AEAD class */
+
+  gaead_aad *(*aad)(const gaead_key */*k*/);
+       /* Return an AAD-hashing object for this key.  Only available if
+        * the @AEADF_AADNDEP@ class flag is clear.
+        */
+
+  gaead_enc *(*enc)(const gaead_key */*k*/,
+                   const void */*n*/, size_t /*nsz*/,
+                   size_t /*hsz*/, size_t /*msz*/, size_t /*tsz*/);
+       /* Return a message encryption object for this key, with the given
+        * nonce.  If the @AEADF_PCHSZ@, @AEADF_PCMSZ@ and/or @AEADF_PCTSZ@
+        * class flags are set then the caller must provide the AAD length
+        * @hsz@, message length @msz@ and/or tag length @tsz@ respectively;
+        * otherwise these arguments will be ignored.
+        *
+        * The caller is expected to have ensured that the nonce and tag
+        * lengths are acceptable, e.g., by checking against the tables
+        * provided in the class object.  Some unfortunate AEAD schemes have
+        * more complicated requirements: if the sizes are unacceptable in
+        * combination, this function returns null.
+        */
+
+  gaead_dec *(*dec)(const gaead_key */*k*/,
+                   const void */*n*/, size_t /*nsz*/,
+                   size_t /*hsz*/, size_t /*csz*/, size_t /*tsz*/);
+       /* Return a message encryption object for this key, with the given
+        * nonce.  If the @AEADF_PCHSZ@, @AEADF_PCMSZ@ and/or @AEADF_PCTSZ@
+        * class flags are set then the caller must provide the AAD length
+        * @hsz@, ciphertext length @csz@ and/or tag length @tsz@
+        * respectively; otherwise these arguments will be ignored.
+        *
+        * The caller is expected to have ensured that the nonce and tag
+        * lengths are acceptable, e.g., by checking against the tables
+        * provided in the class object.  Some unfortunate AEAD schemes have
+        * more complicated requirements: if the sizes are unacceptable in
+        * combination, this function returns null.
+        */
+
+  void (*destroy)(gaead_key */*k*/);
+       /* Destroy the key object.  This will not invalidate AAD-hashing,
+        * encryption or decryption objects.
+        */
+
+} gaead_keyops;
+
+typedef struct gaead_aadops {
+  const struct gcaead *c;              /* Pointer to AEAD class */
+
+  gaead_aad *(*dup)(const gaead_aad */*a*/);
+       /* Return a new AAD-hashing object with a copy of this object's
+        * state.  This is useful if the AAD for multiple messages shares a
+        * common prefix: the prefix can be processed once, and a copy
+        * created for each different suffix.  Only available if the
+        * @AEADF_AADNDEP@ class flag is clear.
+        */
+
+  void (*hash)(gaead_aad */*a*/, const void */*h*/, size_t /*hsz*/);
+       /* Feed header (additional authenticated) data into the AAD-hashing
+        * object.  If the @AEADF_NOAAD@ class flag is set then @hsz@ must be
+        * zero.
+        */
+
+  void (*destroy)(gaead_aad */*a*/);
+       /* Destroy the AAD-hashing object. */
+
+} gaead_aadops;
+
+typedef struct gaead_encops {
+  const struct gcaead *c;              /* Pointer to AEAD class */
+
+  gaead_aad *(*aad)(gaead_enc */*e*/);
+       /* Return a new AAD-hashing object for the current key and nonce.  If
+        * the @AEADF_AADNDEP@ class flag is clear then this works just as if
+        * the @aad@ method on the key had been called instead: the new
+        * object is in fact independent of the nonce and can be used with
+        * any encryption or decryption operation.  If @AEADF_AADNDEP@ is
+        * set, then the returned AAD-hashing object is specific to this
+        * encryption operation.  If @AEADF_AADFIRST@ is also set, then all
+        * additional data must be hashed before any message data is
+        * presented for encryption.
+        */
+
+  int (*reinit)(gaead_enc */*e*/, const void */*n*/, size_t /*nsz*/,
+               size_t /*hsz*/, size_t /*msz*/, size_t /*tsz*/);
+       /* Reinitialize this object for a new encryption operation with a
+        * different nonce.  The data lengths @hsz@, @msz@, and @tsz@ are as
+        * for the key @enc@ method.  Returns zero on success.
+        *
+        * The caller is expected to have ensured that the nonce and tag
+        * lengths are acceptable, e.g., by checking against the tables
+        * provided in the class object.  Some unfortunate AEAD schemes have
+        * more complicated requirements: if the sizes are unacceptable in
+        * combination, this function returns @-1@.
+        */
+
+  int (*encrypt)(gaead_enc */*e*/, const void */*m*/, size_t /*msz*/,
+                buf */*b*/);
+       /* Encrypt a chunk of data, writing the result to the output buffer
+        * @b@.  This will succeed if @BLEFT(b) >= msz + e->c->bufsz@;
+        * otherwise it might fail.  Failure doesn't affect the encryption
+        * operation's state.  Returns zero on success, or @-1@ on failure.
+        */
+
+  int (*done)(gaead_enc */*e*/, const gaead_aad */*a*/, buf */*b*/,
+             void */*t*/, size_t /*tsz*/);
+       /* Completes encryption, returning the authentication tag for the
+        * message and any additional authenticated data accumulated in @a@.
+        * The pointer @a@ may be null if there is no AAD.  If the
+        * @AEADF_AADNDEP@ class flag is set, and any header data has been
+        * provided to the operation's AAD-hashing object, then a pointer to
+        * this object must be provided as @a@.  If @AEADF_AADNDEP@ is clear,
+        * then any AAD-hashing object for this key may be provided.
+        * Internally buffered ciphertext may be written to @b@.  This will
+        * succeed if @BLEFT(b) >= e->c->bufsz@; otherwise it might fail.
+        * Failure doesn't affect the encryption operation's state.  Returns
+        * zero on success, or @-1@ on failure.
+        */
+
+  void (*destroy)(gaead_enc */*e*/);
+       /* Destroy the encryption object. */
+
+} gaead_encops;
+
+typedef struct gaead_decops {
+  const struct gcaead *c;              /* Pointer to AEAD class */
+
+  gaead_aad *(*aad)(gaead_dec */*d*/);
+       /* Return a new AAD-hashing object for the current key and nonce.  If
+        * the @AEADF_AADNDEP@ class flag is clear then this works just as if
+        * the @aad@ method on the key had been called instead: the new
+        * object is in fact independent of the nonce and can be used with
+        * any encryption or decryption operation.  If @AEADF_AADNDEP@ is
+        * set, then the returned AAD-hashing object is specific to this
+        * decryption operation.  If @AEADF_AADFIRST@ is also set, then all
+        * additional data must be hashed before any ciphertext is presented
+        * for decryption.
+        */
+
+  int (*reinit)(gaead_dec */*d*/, const void */*n*/, size_t /*nsz*/,
+               size_t /*hsz*/, size_t /*csz*/, size_t /*tsz*/);
+       /* Reinitialize this object for a new decryption operation with a
+        * different nonce.  The data lengths @hsz@, @csz@, and @tsz@ are as
+        * for the key @dec@ method.
+        *
+        * The caller is expected to have ensured that the nonce and tag
+        * lengths are acceptable, e.g., by checking against the tables
+        * provided in the class object.  Some unfortunate AEAD schemes have
+        * more complicated requirements: if the sizes are unacceptable in
+        * combination, this function returns @-1@.
+        */
+
+  int (*decrypt)(gaead_dec */*d*/, const void */*c*/, size_t /*csz*/,
+                buf */*b*/);
+       /* Decrypt a chunk of data, writing the result to the output buffer
+        * @b@.  This will succeed if @BLEFT(b) >= msz + e->c->bufsz@;
+        * otherwise it might fail.  Failure doesn't affect the decryption
+        * operation's state.  Returns zero on success, or @-1@ on failure.
+        *
+        * CAUTION: the decrypted data may be inauthentic.  Don't do anything
+        * risky with it until its tag has been verified.
+        */
+
+  int (*done)(gaead_dec */*d*/, const gaead_aad */*a*/, buf */*b*/,
+             const void */*t*/, size_t /*tsz*/);
+       /* Completes decryption, verifying the authentication tag for the
+        * message and any additional authenticated data accumulated in @a@.
+        * The pointer @a@ may be null if there is no AAD.  If the
+        * @AEADF_AADNDEP@ class flag is set, and any header data has been
+        * provided to the operation's AAD-hashing object, then a pointer to
+        * this object must be provided as @a@.  If @AEADF_AADNDEP@ is clear,
+        * then any AAD-hashing object for this key may be provided.
+        * Internally buffered plaintext may be written to @b@.  This will
+        * succeed if @BLEFT(b) >= e->c->bufsz@; otherwise it might fail.
+        * Failure doesn't affect the decryption operation's state.  Returns
+        * @+1@ on success, @0@ on verification failure, or @-1@ on other
+        * kinds of failures.
+        */
+
+  void (*destroy)(gaead_dec */*d*/);
+       /* Destroy the decryption object. */
+
+} gaead_decops;
+
+typedef struct gcaead {
+  const char *name;                    /* AEAD scheme name */
+  const octet *keysz;                  /* Acceptable keys-size table */
+  const octet *noncesz;                        /* Acceptable nonce-size table */
+  const octet *tagsz;                  /* Acceptable tag-size table */
+  size_t blksz;                                /* Block size, or zero if none */
+  unsigned bufsz;                      /* Maximum extra msg/ct output */
+  unsigned ohd;                                /* Maximum encryption overhead */
+  unsigned f;                          /* Various other flags */
+#define AEADF_PCHSZ 1u                 /*   Precommit to AAD size */
+#define AEADF_PCMSZ 2u                 /*   Precommit to message size */
+#define AEADF_PCTSZ 4u                 /*   Precommit to tag size */
+#define AEADF_AADNDEP 8u               /*   AAD hash is nonce-dependent */
+#define AEADF_AADFIRST 16u             /*   AAD must precede msg/ct */
+#define AEADF_NOAAD 32u                        /*   AAD is not permitted */
+
+  gaead_key *(*key)(const void */*k*/, size_t /*ksz*/);
+       /* Return a key object (above) with the given key material. */
+
+  int (*szok)(size_t /*nsz*/, size_t /*hsz*/,
+             size_t /*msz*/, size_t /*tsz*/);
+       /* Return true (nonzero) if the given collection of sizes for nonce,
+        * header, message, and tag are acceptable in combination.  Mostly
+        * this will be true if the nonce length and tag size are are
+        * acceptable independently (and the header and message lengths are
+        * irrelevant), but some schemes are more awkward.
+        */
+} gcaead;
+
+#define GAEAD_KEY(cc, k, ksz) (cc)->key((k), (ksz))
+#define GAEAD_CLASS(obj) (obj)->ops->c
+#define GAEAD_AAD(ked) (ked)->ops->aad((ked))
+#define GAEAD_REINIT(ed, n, nsz, hsz, msz, tsz)                                \
+  (ed)->ops->reinit((ed), (n), (nsz), (hsz), (msz), (tsz))
+#define GAEAD_ENC(k, n, nsz, hsz, msz, tsz)                            \
+  (k)->ops->enc((k), (n), (nsz), (hsz), (msz), (tsz))
+#define GAEAD_DEC(k, n, nsz, hsz, msz, tsz)                            \
+  (k)->ops->dec((k), (n), (nsz), (hsz), (msz), (tsz))
+#define GAEAD_DUP(a) (a)->ops->dup((a))
+#define GAEAD_HASH(a, h, hsz) (a)->ops->hash((a), (h), (hsz))
+#define GAEAD_ENCRYPT(e, m, msz, b)                                    \
+  (e)->ops->encrypt((e), (m), (msz), (b))
+#define GAEAD_DECRYPT(d, c, csz, b)                                    \
+  (d)->ops->decrypt((d), (c), (csz), (b))
+#define GAEAD_DONE(ed, aad, b, t, tsz)                                 \
+  (ed)->ops->done((ed), (aad), (b), (t), (tsz))
+#define GAEAD_DESTROY(obj) (obj)->ops->destroy((obj))
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @gaead_szokcommon@ --- *
+ *
+ * Arguments:  @const gcaead *aec@ = pointer to AEAD class
+ *             @size_t nsz@, @size_t hsz@, @size_t msz@, @size_t tsz@ =
+ *                     nonce, header, message, and tag sizes
+ *
+ * Returns:    Nonzero if the sizes are acceptable to the AEAD scheme in
+ *             combination.
+ *
+ * Use:                Generic implementation for sensible AEAD schemes.
+ */
+
+extern int gaead_szokcommon(const gcaead */*aec*/,
+                           size_t /*nsz*/, size_t /*hsz*/,
+                           size_t /*msz*/, size_t /*tsz*/);
+
+/* --- @gaead_encrypt@ --- *
+ *
+ * Arguments:  @const gaead_key *k@ = the AEAD key, already prepared
+ *             @const void *n@, @size_t nsz@ = nonce
+ *             @const void *h@, @size_t hsz@ = additional `header' data
+ *             @const void *m@, @size_t msz@ = message input
+ *             @void *c@, @size_t *csz_input@ = ciphertext output
+ *             @void *t@, @size_t tsz@ = tag output
+ *
+ * Returns:    Zero on success, @-1@ if the output buffer is too small.
+ *
+ * Use:                Encrypts and authenticates a message in a single operation.
+ *             This just saves a bunch of messing about with the various
+ *             @gaead_...@ objects.
+ *
+ *             On entry, @*csz_inout@ should be the capacity of the
+ *             ciphertext buffer; on exit, it will be updated with the
+ *             actual size of ciphertext produced.  The function will not
+ *             fail if @*csz_inout >= msz + k->c->ohd@.
+ */
+
+extern int gaead_encrypt(const gaead_key */*k*/,
+                        const void */*n*/, size_t /*nsz*/,
+                        const void */*h*/, size_t /*hsz*/,
+                        const void */*m*/, size_t /*msz*/,
+                        void */*c*/, size_t */*csz_inout*/,
+                        void */*t*/, size_t /*tsz*/);
+
+/* --- @gaead_decrypt@ --- *
+ *
+ * Arguments:  @const gaead_key *k@ = the AEAD key, already prepared
+ *             @const void *n@, @size_t nsz@ = nonce
+ *             @const void *h@, @size_t hsz@ = additional `header' data
+ *             @const void *c@, @size_t csz@ = ciphertext input
+ *             @void *m@, @size_t *msz_inout@ = message output
+ *             @const void *t@, @size_t tsz@ = tag input
+ *
+ * Returns:    @+1@ if everything is good; zero for authentication failure,
+ *             @-1@ for other problems.
+ *
+ * Use:                Decrypts and verifies a message in a single operation.
+ *             This just saves a bunch of messing about with the various
+ *             @gaead_...@ objects.
+ *
+ *             On entry, @*msz_inout@ should be the capacity of the
+ *             message buffer; on exit, it will be updated with the
+ *             actual size of message produced.  The function will not
+ *             fail if @*msz_inout >= csz@.
+ */
+
+extern int gaead_decrypt(const gaead_key */*k*/,
+                        const void */*n*/, size_t /*nsz*/,
+                        const void */*h*/, size_t /*hsz*/,
+                        const void */*c*/, size_t /*csz*/,
+                        void */*m*/, size_t */*msz_inout*/,
+                        const void */*t*/, size_t /*tsz*/);
+
+/*----- Tables ------------------------------------------------------------*/
+
+extern const gcaead *const gaeadtab[];
+
+/* --- @gaead_byname@ --- *
+ *
+ * Arguments:   @const char *p@ = pointer to name string
+ *
+ * Returns:     The named AEAD class, or null.
+ */
+
+extern const gcaead *gaead_byname(const char */*p*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/gcm-arm-crypto.S b/symm/gcm-arm-crypto.S
new file mode 100644 (file)
index 0000000..ddc714b
--- /dev/null
@@ -0,0 +1,718 @@
+/// -*- mode: asm; asm-comment-char: ?/ -*-
+///
+/// GCM acceleration for ARM processors
+///
+/// (c) 2019 Straylight/Edgeware
+///
+
+///----- Licensing notice ---------------------------------------------------
+///
+/// This file is part of Catacomb.
+///
+/// Catacomb is free software: you can redistribute it and/or modify it
+/// under the terms of the GNU Library General Public License as published
+/// by the Free Software Foundation; either version 2 of the License, or
+/// (at your option) any later version.
+///
+/// Catacomb is distributed in the hope that it will be useful, but
+/// WITHOUT ANY WARRANTY; without even the implied warranty of
+/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+/// Library General Public License for more details.
+///
+/// You should have received a copy of the GNU Library General Public
+/// License along with Catacomb.  If not, write to the Free Software
+/// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+/// USA.
+
+///--------------------------------------------------------------------------
+/// Preliminaries.
+
+#include "config.h"
+#include "asm-common.h"
+
+       .arch   armv8-a
+       .fpu    crypto-neon-fp-armv8
+
+       .text
+
+///--------------------------------------------------------------------------
+/// Multiplication macros.
+
+       // The good news is that we have a fancy instruction to do the
+       // multiplications.  The bad news is that it's not particularly well-
+       // suited to the job.
+       //
+       // For one thing, it only does a 64-bit multiplication, so in general
+       // we'll need to synthesize the full-width multiply by hand.  For
+       // another thing, it doesn't help with the reduction, so we have to
+       // do that by hand too.  And, finally, GCM has crazy bit ordering,
+       // and the instruction does nothing useful for that at all.
+       //
+       // Focusing on that last problem first: the bits aren't in monotonic
+       // significance order unless we permute them.  If we reverse the byte
+       // order, then we'll have the bits in monotonic order, but backwards,
+       // so the degree-0 coefficient will be in the most-significant bit.
+       //
+       // This is less of a difficulty than it seems at first, because
+       // algebra.  Suppose we are given u = SUM_{0<=i<n} u_i t^i and v =
+       // SUM_{0<=j<n} v_j t^j; then
+       //
+       //      u v = SUM_{0<=i,j<n} u_i v_j t^{i+j}
+       //
+       // Suppose instead that we're given ũ = SUM_{0<=i<n} u_{n-i-1} t^i
+       // and ṽ = SUM_{0<=j<n} v_{n-j-1} t^j, so the bits are backwards.
+       // Then
+       //
+       //      ũ ṽ = SUM_{0<=i,j<n} u_{n-i-1} v_{n-j-1} t^{i+j}
+       //          = SUM_{0<=i,j<n} u_i v_j t^{2n-2-(i+j)}
+       //
+       // which is almost the bit-reversal of u v, only it's shifted right
+       // by one place.  Oh, well: we'll have to shift it back later.
+       //
+       // That was important to think about, but there's not a great deal to
+       // do about it yet other than to convert what we've got from the
+       // blockcipher's byte-ordering convention to our big-endian
+       // convention.  Since this depends on the blockcipher convention,
+       // we'll leave the caller to cope with this: the macros here will
+       // assume that the operands are in `register' format, which is the
+       // same as the external representation, except that the bytes within
+       // each 64-bit piece are reversed.  In the commentary, pieces of
+       // polynomial are numbered according to the degree of the
+       // coefficients, so the unit coefficient of some polynomial a is in
+       // a_0.
+       //
+       // The commentary for `mul128' is the most detailed.  The other
+       // macros assume that you've already read and understood that.
+
+.macro mul128
+       // Enter with u and v in q0 and q1 respectively; leave with z = u v
+       // in q0.  Clobbers q1--q3, q8, q9.
+
+       // First for the double-precision multiplication.  It's tempting to
+       // use Karatsuba's identity here, but I suspect that loses more in
+       // the shifting, bit-twiddling, and dependency chains that it gains
+       // in saving a multiplication which otherwise pipelines well.
+       // q0 =                         // (u_0; u_1)
+       // q1 =                         // (v_0; v_1)
+       vmull.p64 q2, d1, d2            // u_1 v_0
+       vmull.p64 q3, d0, d3            // u_0 v_1
+       vmull.p64 q8, d1, d3            // (x_3; t_1) = u_1 v_1
+       vmull.p64 q9, d0, d2            // (t_0; x_0) = u_0 v_0
+
+       // Arrange the pieces to form a double-precision polynomial.
+       veor    q2, q2, q3              // (m_1; m_0) = u_0 v_1 + u_1 v_0
+       veor    d17, d17, d4            // x_2 = t_1 + m_1
+       veor    d18, d18, d5            // x_1 = t_0 + m_0
+       // q8 =                         // (x_3; x_2)
+       // q9 =                         // (x_1; x_0)
+
+       // Two-and-a-half problems remain.  The first is that this product is
+       // shifted left by one place, which is annoying.  Let's take care of
+       // that now.  Once this is done, we'll be properly in GCM's backwards
+       // bit-ordering.
+       //
+       // The half a problem is that the result wants to have its 64-bit
+       // halves switched.  Here turns out to be the best place to arrange
+       // for that.
+       //
+       //                   q9                             q8
+       //      ,-------------.-------------.  ,-------------.-------------.
+       //      | 0  x_0-x_62 | x_63-x_126  |  | x_127-x_190 | x_191-x_254 |
+       //      `-------------^-------------'  `-------------^-------------'
+       //            d19           d18              d17           d16
+       //
+       // We start by shifting each 32-bit lane right (from GCM's point of
+       // view -- physically, left) by one place, which gives us this:
+       //
+       //                 low (q9)                      high (q8)
+       //      ,-------------.-------------.  ,-------------.-------------.
+       //      | x_0-x_62  0 |x_64-x_126 0 |  |x_128-x_190 0|x_192-x_254 0|
+       //      `-------------^-------------'  `-------------^-------------'
+       //            d19           d18              d17           d16
+       //
+       // but we've lost a bunch of bits.  We separately shift each lane
+       // left by 31 places to give us the bits we lost.
+       //
+       //                 low (q3)                      high (q2)
+       //      ,-------------.-------------.  ,-------------.-------------.
+       //      |    0...0    | 0...0  x_63 |  | 0...0 x_127 | 0...0 x_191 |
+       //      `-------------^-------------'  `-------------^-------------'
+       //                           d6              d5            d4
+       //
+       // Since we can address each of these pieces individually, putting
+       // them together is relatively straightforward.
+
+
+       vshr.u64 d6, d18, #63           // shifted left; just the carries
+       vshl.u64 q9, q9, #1             // shifted right, but dropped carries
+       vshr.u64 q2, q8, #63
+       vshl.u64 q8, q8, #1
+       vorr    d0, d19, d6             // y_0
+       vorr    d1, d18, d5             // y_1
+       vorr    d2, d17, d4             // y_2
+       vmov    d3, d16                 // y_3
+
+       // And the other one is that the result needs to be reduced modulo
+       // p(t) = t^128 + t^7 + t^2 + t + 1.  Let R = t^128 = t^7 + t^2 + t +
+       // 1 in our field.  So far, we've calculated z_0 and z_1 such that
+       // z_0 + z_1 R = u v using the identity R = t^128: now we must
+       // collapse the two halves of y together using the other identity R =
+       // t^7 + t^2 + t + 1.
+       //
+       // We do this by working on y_2 and y_3 separately, so consider y_i
+       // for i = 2 or 3.  Certainly, y_i t^{64i} = y_i R t^{64(i-2) =
+       // (t^7 + t^2 + t + 1) y_i t^{64(i-2)}, but we can't use that
+       // directly without breaking up the 64-bit word structure.  Instead,
+       // we start by considering just y_i t^7 t^{64(i-2)}, which again
+       // looks tricky.  Now, split y_i = a_i + t^57 b_i, with deg a_i < 57;
+       // then
+       //
+       //      y_i t^7 t^{64(i-2)} = a_i t^7 t^{64(i-2)} + b_i t^{64(i-1)}
+       //
+       // We can similarly decompose y_i t^2 and y_i t into a pair of 64-bit
+       // contributions to the t^{64(i-2)} and t^{64(i-1)} words, but the
+       // splits are different.  This is lovely, with one small snag: when
+       // we do this to y_3, we end up with a contribution back into the
+       // t^128 coefficient word.  But notice that only the low seven bits
+       // of this word are affected, so there's no knock-on contribution
+       // into the t^64 word.  Therefore, if we handle the high bits of each
+       // word together, and then the low bits, everything will be fine.
+
+       // First, shift the high bits down.
+       vshl.u64 q2, q1, #63            // the b_i for t
+       vshl.u64 q3, q1, #62            // the b_i for t^2
+       vshl.u64 q8, q1, #57            // the b_i for t^7
+       veor    q2, q2, q3              // add them all together
+       veor    q2, q2, q8
+       veor    d2, d2, d5              // contribution into low half
+       veor    d1, d1, d4              // and high half
+
+       // And then shift the low bits up.
+       vshr.u64 q2, q1, #1
+       vshr.u64 q3, q1, #2
+       vshr.u64 q8, q1, #7
+       veor    q0, q0, q1              // mix in the unit contribution
+       veor    q2, q2, q3              // t and t^2 contribs
+       veor    q0, q0, q8              // low, unit, and t^7 contribs
+       veor    q0, q0, q2              // mix them together and we're done
+.endm
+
+.macro mul64
+       // Enter with u and v in the low halves of d0 and d1 respectively;
+       // leave with z = u v in d0.  Clobbers d1--d5.
+
+       // The multiplication is thankfully easy.
+       vmull.p64 q0, d0, d1            // u v
+
+       // Shift the product up by one place, and swap the two halves.  After
+       // this, we're in GCM bizarro-world.
+       vshr.u64 d2, d0, #63            // shifted left; just the carries
+       vshl.u64 d3, d1, #1             // low half right
+       vshl.u64 d1, d0, #1             // high half shifted right
+       vorr    d0, d3, d2              // mix in the carries
+
+       // Now we must reduce.  This is essentially the same as the 128-bit
+       // case above, but mostly simpler because everything is smaller.  The
+       // polynomial this time is p(t) = t^64 + t^4 + t^3 + t + 1.
+
+       // First, shift the high bits down.
+       vshl.u64 d2, d1, #63            // b_i for t
+       vshl.u64 d3, d1, #61            // b_i for t^3
+       vshl.u64 d4, d1, #60            // b_i for t^4
+       veor    d2, d2, d3              // add them all together
+       veor    d2, d2, d4
+       veor    d1, d1, d2              // contribution back into high half
+
+       // And then shift the low bits up.
+       vshr.u64 d2, d1, #1
+       vshr.u64 d3, d1, #3
+       vshr.u64 d4, d1, #4
+       veor    d0, d0, d1              // mix in the unit contribution
+       veor    d2, d2, d3              // t and t^3 contribs
+       veor    d0, d0, d4              // low, unit, and t^4
+       veor    d0, d0, d2              // mix them together and we're done
+.endm
+
+.macro mul96
+       // Enter with u and v in the most-significant three words of q0 and
+       // q1 respectively, and zero in the low words, and zero in q15; leave
+       // with z = u v in the high three words of q0, and /junk/ in the low
+       // word.  Clobbers ???.
+
+       // This is an inconvenient size.  There's nothing for it but to do
+       // four multiplications, as if for the 128-bit case.  It's possible
+       // that there's cruft in the top 32 bits of the input registers, so
+       // shift both of them up by four bytes before we start.  This will
+       // mean that the high 64 bits of the result (from GCM's viewpoint)
+       // will be zero.
+       // q0 =                         // (u_0 + u_1 t^32; u_2)
+       // q1 =                         // (v_0 + v_1 t^32; v_2)
+       vmull.p64 q8, d1, d2            // u_2 (v_0 + v_1 t^32) = e_0
+       vmull.p64 q9, d0, d3            // v_2 (u_0 + u_1 t^32) = e_1
+       vmull.p64 q3, d1, d3            // u_2 v_2 t^64 = d = (0; d)
+       vmull.p64 q0, d0, d2            // u_0 v_0 + (u_0 v_1 + u_1 v_0) t^32
+                                       //   + u_1 v_1 t^64 = f
+
+       // Extract the high and low halves of the 192-bit result.  The answer
+       // we want is d t^128 + e t^64 + f, where e = e_0 + e_1.  The low 96
+       // bits of the answer will end up in q0, and the high 96 bits will
+       // end up in q1; we'll need both of these to have zero in their
+       // bottom 32 bits.
+       //
+       // Here, bot(x) is the low 96 bits of a 192-bit quantity x, arranged
+       // in the low 96 bits of a SIMD register, with junk in the top 32
+       // bits; and top(x) is the high 96 bits, also arranged in the low 96
+       // bits of a register, with /zero/ in the top 32 bits.
+       veor    q8, q8, q9              // e_0 + e_1 = e
+       vshr128 q1, q3, 32              // top(d t^128)
+       vext.8  d19, d16, d17, #4       // top(e t^64)
+       vshl.u64 d16, d0, #32           // top(f), sort of
+       veor    d3, d3, d19             // q1 = top(d t^128 + e t^64)
+       veor    d0, d0, d17             // q0 = bot([d t^128] + e t^64 + f)
+       veor    d3, d3, d16             // q1 = top(d t^128 + e t^64 + f)
+
+       // Shift the product right by one place (from GCM's point of view),
+       // but, unusually, don't swap the halves, because we need to work on
+       // the 32-bit pieces later.  After this, we're in GCM bizarro-world.
+       // q0 =                         // (?, x_2; x_1, x_0)
+       // q1 =                         // (0, x_5; x_4, x_3)
+       vshr.u64 d4, d0, #63            // carry from d0 to d1
+       vshr.u64 d5, d2, #63            // carry from d2 to d3
+       vshr.u32 d6, d3, #31            // carry from d3 to d0
+       vshl.u64 q0, q0, #1             // shift low half
+       vshl.u64 q1, q1, #1             // shift high half
+       vorr    d1, d1, d4
+       vorr    d0, d0, d6
+       vorr    d3, d3, d5
+
+       // Finally, the reduction.  This is essentially the same as the
+       // 128-bit case, except that the polynomial is p(t) = t^96 + t^10 +
+       // t^9 + t^6 + 1.  The degrees are larger but not enough to cause
+       // trouble for the general approach.
+
+       // First, shift the high bits down.
+       vshl.u32 q2, q1, #26            // b_i for t^6
+       vshl.u32 q3, q1, #23            // b_i for t^9
+       vshl.u32 q8, q1, #22            // b_i for t^10
+       veor    q2, q2, q3              // add them all together
+       veor    q2, q2, q8
+       vshl128 q3, q2, 64              // contribution into high half
+       vshr128 q2, q2, 32              // and low half
+       veor    q1, q1, q3              // mix them in
+       veor    q0, q0, q2
+
+       // And then shift the low bits up.
+       vshr.u32 q2, q1, #6
+       vshr.u32 q3, q1, #9
+       veor    q0, q0, q1              // mix in the unit contribution
+       vshr.u32 q8, q1, #10
+       veor    q2, q2, q3              // mix together t^6 and t^9
+       veor    q0, q0, q8              // mix in t^10
+       veor    q0, q0, q2              // and the rest
+
+       // And finally swap the two halves.
+       vswp    d0, d1
+.endm
+
+.macro mul192
+       // Enter with u and v in d0--d2 and d3--d5 respectively; leave
+       // with z = u v in d0--d2.  Clobbers q8--q15.
+
+       // Start multiplying and accumulating pieces of product.
+       // (d0; d1; d2) =               // (u_0; u_1; u_2)
+       // (d3; d4; d5) =               // (v_0; v_1; v_2)
+       vmull.p64 q10, d0, d3           // e = u_0 v_0
+
+       vmull.p64 q12, d0, d4           //     u_0 v_1
+       vmull.p64 q13, d1, d3           //     u_1 v_0
+
+       vmull.p64 q9, d0, d5            //     u_0 v_2
+       vmull.p64 q14, d1, d4           //     u_1 v_1
+       vmull.p64 q15, d2, d3           //     u_2 v_0
+        veor   q12, q12, q13           // d = u_0 v_1 + u_1 v_0
+
+       vmull.p64 q11, d1, d5           //     u_1 v_2
+       vmull.p64 q13, d2, d4           //     u_2 v_1
+        veor   q9, q9, q14             //     u_0 v_2 + u_1 v_1
+
+       vmull.p64 q8, d2, d5            // a = u_2 v_2
+        veor   q9, q9, q15             // c = u_0 v_2 + u_1 v_1 + u_2 v_0
+        veor   q11, q11, q13           // b = u_1 v_2 + u_2 v_1
+
+       // Piece the product together.
+       veor    d17, d17, d22  //  q8 = // (x_5; x_4)
+       veor    d18, d18, d23
+       veor    d19, d19, d24  //  q9 = // (x_3; x_2)
+       veor    d20, d20, d25  // q10 = // (x_1; x_0)
+
+       // Shift the product right by one place (from GCM's point of view).
+       vshr.u64 q11, q8, #63           // carry from d16/d17 to d17/d18
+       vshr.u64 q12, q9, #63           // carry from d18/d19 to d19/d20
+       vshr.u64 d26, d20, #63          // carry from d20 to d21
+       vshl.u64 q8, q8, #1             // shift everything down
+       vshl.u64 q9, q9, #1
+       vshl.u64 q10, q10, #1
+       vorr    d17, d17, d22           // and mix in the carries
+       vorr    d18, d18, d23
+       vorr    d19, d19, d24
+       vorr    d20, d20, d25
+       vorr    d21, d21, d26
+
+       // Next, the reduction.  Our polynomial this time is p(x) = t^192 +
+       // t^7 + t^2 + t + 1.  Yes, the magic numbers are the same as the
+       // 128-bit case.  I don't know why.
+
+       // First, shift the high bits down.
+       // q8 =                         // (y_5; y_4)
+       // q9 =                         // (y_3; y_2)
+       // q10 =                        // (y_1; y_0)
+       vshl.u64 q11, q8, #63           // (y_5; y_4) b_i for t
+       vshl.u64 d28, d18, #63          // y_3 b_i for t
+       vshl.u64 q12, q8, #62           // (y_5; y_4) b_i for t^2
+       vshl.u64 d29, d18, #62          // y_3 b_i for t^2
+       vshl.u64 q13, q8, #57           // (y_5; y_4) b_i for t^7
+       vshl.u64 d30, d18, #57          // y_3 b_i for t^7
+       veor    q11, q11, q12           // mix them all together
+       veor    d28, d28, d29
+       veor    q11, q11, q13
+       veor    d28, d28, d30
+       veor    q9, q9, q11
+       veor    d20, d20, d28
+
+       // And finally shift the low bits up.  Also, switch the order of the
+       // pieces for output.
+       // q8 =                         // (y'_5; y'_4)
+       // q9 =                         // (y'_3; y'_2)
+       // q10 =                        // (y'_1; y'_0)
+       vshr.u64 q11, q8, #1            // (y_5; y_4) a_i for t
+       vshr.u64 d28, d18, #1           // y'_3 a_i for t
+       vshr.u64 q12, q8, #2            // (y_5; y_4) a_i for t^2
+       vshr.u64 d29, d18, #2           // y'_3 a_i for t^2
+       vshr.u64 q13, q8, #7            // (y_5; y_4) a_i for t^7
+       vshr.u64 d30, d18, #7           // y'_3 a_i for t^7
+       veor    q8, q8, q11
+       veor    d18, d18, d28
+       veor    q12, q12, q13
+       veor    d29, d29, d30
+       veor    q8, q8, q12
+       veor    d18, d18, d29
+       veor    d0, d21, d18
+       veor    d1, d20, d17
+       veor    d2, d19, d16
+.endm
+
+.macro mul256
+       // Enter with u and v in q0/q1 and q2/q3 respectively; leave
+       // with z = u v in q0/q1.  Clobbers q8--q15.
+
+       // Now it's starting to look worthwhile to do Karatsuba.  Suppose
+       // u = u_0 + u_1 B and v = v_0 + v_1 B.  Then
+       //
+       //      u v = (u_0 v_0) + (u_0 v_1 + u_1 v_0) B + (u_1 v_1) B^2
+       //
+       // Name these coefficients of B^i be a, b, and c, respectively, and
+       // let r = u_0 + u_1 and s = v_0 + v_1.  Then observe that
+       //
+       //      q = r s = (u_0 + u_1) (v_0 + v_1)
+       //        = (u_0 v_0) + (u1 v_1) + (u_0 v_1 + u_1 v_0)
+       //        = a + d + c
+       //
+       // The first two terms we've already calculated; the last is the
+       // remaining one we want.  We'll set B = t^128.  We know how to do
+       // 128-bit multiplications already, and Karatsuba is too annoying
+       // there, so there'll be 12 multiplications altogether, rather than
+       // the 16 we'd have if we did this the naïve way.
+       // q0 =                         // u_0 = (u_00; u_01)
+       // q1 =                         // u_1 = (u_10; u_11)
+       // q2 =                         // v_0 = (v_00; v_01)
+       // q3 =                         // v_1 = (v_10; v_11)
+
+       veor    q8, q0, q1              // u_* = (u_00 + u_10; u_01 + u_11)
+       veor    q9, q2, q3              // v_* = (v_00 + v_10; v_01 + v_11)
+
+       // Start by building the cross product, q = u_* v_*.
+       vmull.p64 q14, d16, d19         // u_*0 v_*1
+       vmull.p64 q15, d17, d18         // u_*1 v_*0
+       vmull.p64 q12, d17, d19         // u_*1 v_*1
+       vmull.p64 q13, d16, d18         // u_*0 v_*0
+       veor    q14, q14, q15           // u_*0 v_*1 + u_*1 v_*0
+       veor    d25, d25, d28  // q12 = // q_1
+       veor    d26, d26, d29  // q13 = // q_0
+
+       // Next, work on the low half, a = u_0 v_0.
+       vmull.p64 q14, d0, d5           // u_00 v_01
+       vmull.p64 q15, d1, d4           // u_01 v_00
+       vmull.p64 q10, d1, d5           // u_01 v_01
+       vmull.p64 q11, d0, d4           // u_00 v_00
+       veor    q14, q14, q15           // u_00 v_01 + u_01 v_00
+       veor    d21, d21, d28  // q10 = // a_1
+       veor    d22, d22, d29  // q11 = // a_0
+
+       // Mix the pieces we have so far.
+       veor    q12, q12, q10
+       veor    q13, q13, q11
+
+       // Finally, the high half, c = u_1 v_1.
+       vmull.p64 q14, d2, d7           // u_10 v_11
+       vmull.p64 q15, d3, d6           // u_11 v_10
+       vmull.p64 q8, d3, d7            // u_11 v_11
+       vmull.p64 q9, d2, d6            // u_10 v_10
+       veor    q14, q14, q15           // u_10 v_11 + u_11 v_10
+       veor    d17, d17, d28  //  q8 = // c_1
+       veor    d18, d18, d29  //  q9 = // c_0
+
+       // Finish mixing the product together.
+       veor    q12, q12, q8   // q12 = // b_1
+       veor    q13, q13, q9   // q13 = // b_0
+       veor    q9, q9, q12
+       veor    q10, q10, q13
+
+       // Shift the product right by one place (from GCM's point of view).
+       vshr.u64 q0, q8, #63            // carry from d16/d17 to d17/d18
+       vshr.u64 q1, q9, #63            // carry from d18/d19 to d19/d20
+       vshr.u64 q2, q10, #63           // carry from d20/d21 to d21/d22
+       vshr.u64 d6, d22, #63           // carry from d22 to d23
+       vshl.u64 q8, q8, #1             // shift everyting down
+       vshl.u64 q9, q9, #1
+       vshl.u64 q10, q10, #1
+       vshl.u64 q11, q11, #1
+       vorr    d17, d17, d0
+       vorr    d18, d18, d1
+       vorr    d19, d19, d2
+       vorr    d20, d20, d3
+       vorr    d21, d21, d4
+       vorr    d22, d22, d5
+       vorr    d23, d23, d6
+
+       // Now we must reduce.  This is essentially the same as the 192-bit
+       // case above, but more complicated because everything is bigger.
+       // The polynomial this time is p(t) = t^256 + t^10 + t^5 + t^2 + 1.
+
+       // First, shift the high bits down.
+       // q8 =                         // (y_7; y_6)
+       // q9 =                         // (y_5; y_4)
+       // q10 =                        // (y_3; y_2)
+       // q11 =                        // (y_1; y_0)
+       vshl.u64 q0, q8, #62            // (y_7; y_6) b_i for t^2
+       vshl.u64 q12, q9, #62           // (y_5; y_4) b_i for t^2
+       vshl.u64 q1, q8, #59            // (y_7; y_6) b_i for t^5
+       vshl.u64 q13, q9, #59           // (y_5; y_4) b_i for t^5
+       vshl.u64 q2, q8, #54            // (y_7; y_6) b_i for t^10
+       vshl.u64 q14, q9, #54           // (y_5; y_4) b_i for t^10
+       veor    q0, q0, q1              // mix the contributions together
+       veor    q12, q12, q13
+       veor    q0, q0, q2
+       veor    q12, q12, q14
+       veor    d19, d19, d0            // and combine into the lower pieces
+       veor    d20, d20, d1
+       veor    d21, d21, d24
+       veor    d22, d22, d25
+
+       // And then shift the low bits up.  Also, switch the order of the
+       // pieces for output.
+       // q8 =                         // (y'_7; y'_6)
+       // q9 =                         // (y'_5; y'_4)
+       // q10 =                        // (y'_3; y'_2)
+       // q11 =                        // (y'_1; y'_0)
+       vshr.u64 q0, q8, #2             // (y_7; y_6) a_i for t^2
+       vshr.u64 q12, q9, #2            // (y_5; y'_4) a_i for t^2
+       vshr.u64 q1, q8, #5             // (y_7; y_6) a_i for t^5
+       vshr.u64 q13, q9, #5            // (y_5; y_4) a_i for t^5
+       vshr.u64 q2, q8, #10            // (y_7; y_6) a_i for t^10
+       vshr.u64 q14, q9, #10           // (y_5; y_4) a_i for t^10
+
+       veor    q8, q8, q0              // mix the contributions together
+       veor    q1, q1, q2
+       veor    q9, q9, q12
+       veor    q13, q13, q14
+       veor    q8, q8, q1
+       veor    q9, q9, q13
+       veor    d3, d20, d16            // and output
+       veor    d2, d21, d17
+       veor    d1, d22, d18
+       veor    d0, d23, d19
+.endm
+
+///--------------------------------------------------------------------------
+/// Main code.
+
+// There are a number of representations of field elements in this code and
+// it can be confusing.
+//
+//   * The `external format' consists of a sequence of contiguous bytes in
+//     memory called a `block'.  The GCM spec explains how to interpret this
+//     block as an element of a finite field.  As discussed extensively, this
+//     representation is very annoying for a number of reasons.  On the other
+//     hand, this code never actually deals with it directly.
+//
+//   * The `register format' consists of one or more NEON registers,
+//     depending on the block size.  The bytes in each 64-bit lane of these
+//     registers are in reverse order, compared to the external format.
+//
+//   * The `words' format consists of a sequence of bytes, as in the
+//     `external format', but, according to the blockcipher in use, the bytes
+//     within each 32-bit word may be reversed (`big-endian') or not
+//     (`little-endian').  Accordingly, there are separate entry points for
+//     each variant, identified with `b' or `l'.
+
+FUNC(gcm_mulk_128b_arm_crypto)
+       // On entry, r0 points to a 128-bit field element A in big-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {q0}, [r0]
+       vld1.8  {q1}, [r1]
+       vrev64.32 q0, q0
+       mul128
+       vrev64.32 q0, q0
+       vst1.8  {q0}, [r0]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_128l_arm_crypto)
+       // On entry, r0 points to a 128-bit field element A in little-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {q0}, [r0]
+       vld1.8  {q1}, [r1]
+       vrev64.8 q0, q0
+       mul128
+       vrev64.8 q0, q0
+       vst1.8  {q0}, [r0]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_64b_arm_crypto)
+       // On entry, r0 points to a 64-bit field element A in big-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {d0}, [r0]
+       vld1.8  {d1}, [r1]
+       vrev64.32 d0, d0
+       mul64
+       vrev64.32 d0, d0
+       vst1.8  {d0}, [r0]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_64l_arm_crypto)
+       // On entry, r0 points to a 64-bit field element A in little-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {d0}, [r0]
+       vld1.8  {d1}, [r1]
+       vrev64.8 d0, d0
+       vzero
+       mul64
+       vrev64.8 d0, d0
+       vst1.8  {d0}, [r0]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_96b_arm_crypto)
+       // On entry, r0 points to a 96-bit field element A in big-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       ldr     r3, [r0, #8]
+       mov     r12, #0
+       vld1.8  {d0}, [r0]
+       vld1.8  {q1}, [r1]
+       vrev64.32 d0, d0
+       vmov    d1, r12, r3
+       vzero
+       mul96
+       vrev64.32 d0, d0
+       vmov    r3, d1[1]
+       vst1.8  {d0}, [r0]
+       str     r3, [r0, #8]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_96l_arm_crypto)
+       // On entry, r0 points to a 128-bit field element A in little-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       ldr     r3, [r0, #8]
+       mov     r12, #0
+       vld1.8  {d0}, [r0]
+       vld1.8  {q1}, [r1]
+       vmov    d1, r3, r12
+       vrev64.8 q0, q0
+       mul96
+       vrev64.8 q0, q0
+       vmov    r3, d1[0]
+       vst1.8  {d0}, [r0]
+       str     r3, [r0, #8]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_192b_arm_crypto)
+       // On entry, r0 points to a 192-bit field element A in big-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {d0-d2}, [r0]
+       vld1.8  {d3-d5}, [r1]
+       vrev64.32 q0, q0
+       vrev64.32 d2, d2
+       mul192
+       vrev64.32 q0, q0
+       vrev64.32 d2, d2
+       vst1.8  {d0-d2}, [r0]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_192l_arm_crypto)
+       // On entry, r0 points to a 192-bit field element A in little-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {d0-d2}, [r0]
+       vld1.8  {d3-d5}, [r1]
+       vrev64.8 q0, q0
+       vrev64.8 d2, d2
+       mul192
+       vrev64.8 q0, q0
+       vrev64.8 d2, d2
+       vst1.8  {d0-d2}, [r0]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_256b_arm_crypto)
+       // On entry, r0 points to a 256-bit field element A in big-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {q0, q1}, [r0]
+       vld1.8  {q2, q3}, [r1]
+       vrev64.32 q0, q0
+       vrev64.32 q1, q1
+       mul256
+       vrev64.32 q0, q0
+       vrev64.32 q1, q1
+       vst1.8  {q0, q1}, [r0]
+       bx      r14
+ENDFUNC
+
+FUNC(gcm_mulk_256l_arm_crypto)
+       // On entry, r0 points to a 256-bit field element A in little-endian
+       // words format; r1 points to a field-element K in register format.
+       // On exit, A is updated with the product A K.
+
+       vld1.8  {q0, q1}, [r0]
+       vld1.8  {q2, q3}, [r1]
+       vrev64.8 q0, q0
+       vrev64.8 q1, q1
+       mul256
+       vrev64.8 q0, q0
+       vrev64.8 q1, q1
+       vst1.8  {q0, q1}, [r0]
+       bx      r14
+ENDFUNC
+
+///----- That's all, folks --------------------------------------------------
diff --git a/symm/gcm-arm64-pmull.S b/symm/gcm-arm64-pmull.S
new file mode 100644 (file)
index 0000000..97bb3bf
--- /dev/null
@@ -0,0 +1,661 @@
+/// -*- mode: asm; asm-comment-char: ?/ -*-
+///
+/// GCM acceleration for ARM64 processors
+///
+/// (c) 2019 Straylight/Edgeware
+///
+
+///----- Licensing notice ---------------------------------------------------
+///
+/// This file is part of Catacomb.
+///
+/// Catacomb is free software: you can redistribute it and/or modify it
+/// under the terms of the GNU Library General Public License as published
+/// by the Free Software Foundation; either version 2 of the License, or
+/// (at your option) any later version.
+///
+/// Catacomb is distributed in the hope that it will be useful, but
+/// WITHOUT ANY WARRANTY; without even the implied warranty of
+/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+/// Library General Public License for more details.
+///
+/// You should have received a copy of the GNU Library General Public
+/// License along with Catacomb.  If not, write to the Free Software
+/// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+/// USA.
+
+///--------------------------------------------------------------------------
+/// Preliminaries.
+
+#include "config.h"
+#include "asm-common.h"
+
+       .arch   armv8-a+crypto
+
+       .text
+
+///--------------------------------------------------------------------------
+/// Multiplication macros.
+
+       // The good news is that we have a fancy instruction to do the
+       // multiplications.  The bad news is that it's not particularly well-
+       // suited to the job.
+       //
+       // For one thing, it only does a 64-bit multiplication, so in general
+       // we'll need to synthesize the full-width multiply by hand.  For
+       // another thing, it doesn't help with the reduction, so we have to
+       // do that by hand too.  And, finally, GCM has crazy bit ordering,
+       // and the instruction does nothing useful for that at all.
+       //
+       // Focusing on that last problem first: the bits aren't in monotonic
+       // significance order unless we permute them.  Fortunately, ARM64 has
+       // an instruction which will just permute the bits in each byte for
+       // us, so we don't have to worry about this very much.
+       //
+       // Our main weapons, the `pmull' and `pmull2' instructions, work on
+       // 64-bit operands, in half of a vector register, and produce 128-bit
+       // results.  But neither of them will multiply the high half of one
+       // vector by the low half of a second one, so we have a problem,
+       // which we solve by representing one of the operands redundantly:
+       // rather than packing the 64-bit pieces together, we duplicate each
+       // 64-bit piece across both halves of a register.
+       //
+       // The commentary for `mul128' is the most detailed.  The other
+       // macros assume that you've already read and understood that.
+
+.macro mul128
+       // Enter with u and v in v0 and v1/v2 respectively, and 0 in v31;
+       // leave with z = u v in v0.  Clobbers v1--v6.
+
+       // First for the double-precision multiplication.  It's tempting to
+       // use Karatsuba's identity here, but I suspect that loses more in
+       // the shifting, bit-twiddling, and dependency chains that it gains
+       // in saving a multiplication which otherwise pipelines well.
+       // v0 =                         // (u_0; u_1)
+       // v1/v2 =                      // (v_0; v_1)
+       pmull2  v3.1q, v0.2d, v1.2d     // u_1 v_0
+       pmull   v4.1q, v0.1d, v2.1d     // u_0 v_1
+       pmull2  v5.1q, v0.2d, v2.2d     // (t_1; x_3) = u_1 v_1
+       pmull   v6.1q, v0.1d, v1.1d     // (x_0; t_0) = u_0 v_0
+
+       // Arrange the pieces to form a double-precision polynomial.
+       eor     v3.16b, v3.16b, v4.16b  // (m_0; m_1) = u_0 v_1 + u_1 v_0
+       vshr128 v4, v3, 64              // (m_1; 0)
+       vshl128 v3, v3, 64              // (0; m_0)
+       eor     v1.16b, v5.16b, v4.16b  // (x_2; x_3)
+       eor     v0.16b, v6.16b, v3.16b  // (x_0; x_1)
+
+       // And now the only remaining difficulty is that the result needs to
+       // be reduced modulo p(t) = t^128 + t^7 + t^2 + t + 1.  Let R = t^128
+       // = t^7 + t^2 + t + 1 in our field.  So far, we've calculated z_0
+       // and z_1 such that z_0 + z_1 R = u v using the identity R = t^128:
+       // now we must collapse the two halves of y together using the other
+       // identity R = t^7 + t^2 + t + 1.
+       //
+       // We do this by working on y_2 and y_3 separately, so consider y_i
+       // for i = 2 or 3.  Certainly, y_i t^{64i} = y_i R t^{64(i-2) =
+       // (t^7 + t^2 + t + 1) y_i t^{64(i-2)}, but we can't use that
+       // directly without breaking up the 64-bit word structure.  Instead,
+       // we start by considering just y_i t^7 t^{64(i-2)}, which again
+       // looks tricky.  Now, split y_i = a_i + t^57 b_i, with deg a_i < 57;
+       // then
+       //
+       //      y_i t^7 t^{64(i-2)} = a_i t^7 t^{64(i-2)} + b_i t^{64(i-1)}
+       //
+       // We can similarly decompose y_i t^2 and y_i t into a pair of 64-bit
+       // contributions to the t^{64(i-2)} and t^{64(i-1)} words, but the
+       // splits are different.  This is lovely, with one small snag: when
+       // we do this to y_3, we end up with a contribution back into the
+       // t^128 coefficient word.  But notice that only the low seven bits
+       // of this word are affected, so there's no knock-on contribution
+       // into the t^64 word.  Therefore, if we handle the high bits of each
+       // word together, and then the low bits, everything will be fine.
+
+       // First, shift the high bits down.
+       ushr    v2.2d, v1.2d, #63       // the b_i for t
+       ushr    v3.2d, v1.2d, #62       // the b_i for t^2
+       ushr    v4.2d, v1.2d, #57       // the b_i for t^7
+       eor     v2.16b, v2.16b, v3.16b  // add them all together
+       eor     v2.16b, v2.16b, v4.16b
+       vshr128 v3, v2, 64
+       vshl128 v4, v2, 64
+       eor     v1.16b, v1.16b, v3.16b  // contribution into high half
+       eor     v0.16b, v0.16b, v4.16b  // and low half
+
+       // And then shift the low bits up.
+       shl     v2.2d, v1.2d, #1
+       shl     v3.2d, v1.2d, #2
+       shl     v4.2d, v1.2d, #7
+       eor     v1.16b, v1.16b, v2.16b  // unit and t contribs
+       eor     v3.16b, v3.16b, v4.16b  // t^2 and t^7 contribs
+       eor     v0.16b, v0.16b, v1.16b  // mix everything together
+       eor     v0.16b, v0.16b, v3.16b  // ... and we're done
+.endm
+
+.macro mul64
+       // Enter with u and v in the low halves of v0 and v1, respectively;
+       // leave with z = u v in x2.  Clobbers x2--x4.
+
+       // The multiplication is thankfully easy.
+       // v0 =                                 // (u; ?)
+       // v1 =                                 // (v; ?)
+       pmull   v0.1q, v0.1d, v1.1d             // u v
+
+       // Now we must reduce.  This is essentially the same as the 128-bit
+       // case above, but mostly simpler because everything is smaller.  The
+       // polynomial this time is p(t) = t^64 + t^4 + t^3 + t + 1.
+
+       // Before we get stuck in, transfer the product to general-purpose
+       // registers.
+       mov     x3, v0.d[1]
+       mov     x2, v0.d[0]
+
+       // First, shift the high bits down.
+       eor     x4, x3, x3, lsr #1      // pre-mix t^3 and t^4
+       eor     x3, x3, x3, lsr #63     // mix in t contribution
+       eor     x3, x3, x4, lsr #60     // shift and mix in t^3 and t^4
+
+       // And then shift the low bits up.
+       eor     x3, x3, x3, lsl #1      // mix unit and t; pre-mix t^3, t^4
+       eor     x2, x2, x3              // fold them in
+       eor     x2, x2, x3, lsl #3      // and t^3 and t^4
+.endm
+
+.macro mul96
+       // Enter with u in the least-significant 96 bits of v0, with zero in
+       // the upper 32 bits, and with the least-significant 64 bits of v in
+       // both halves of v1, and the upper 32 bits of v in the low 32 bits
+       // of each half of v2, with zero in the upper 32 bits; and with zero
+       // in v31.  Yes, that's a bit hairy.  Leave with the product u v in
+       // the low 96 bits of v0, and /junk/ in the high 32 bits.  Clobbers
+       // v1--v6.
+
+       // This is an inconvenient size.  There's nothing for it but to do
+       // four multiplications, as if for the 128-bit case.  It's possible
+       // that there's cruft in the top 32 bits of the input registers, so
+       // shift both of them up by four bytes before we start.  This will
+       // mean that the high 64 bits of the result (from GCM's viewpoint)
+       // will be zero.
+       // v0 =                         // (u_0 + u_1 t^32; u_2)
+       // v1 =                         // (v_0 + v_1 t^32; v_0 + v_1 t^32)
+       // v2 =                         // (v_2; v_2)
+       pmull2  v5.1q, v0.2d, v1.2d     // u_2 (v_0 + v_1 t^32) t^32 = e_0
+       pmull   v4.1q, v0.1d, v2.1d     // v_2 (u_0 + u_1 t^32) t^32 = e_1
+       pmull2  v6.1q, v0.2d, v2.2d     // u_2 v_2 = d = (d; 0)
+       pmull   v3.1q, v0.1d, v1.1d     // u_0 v_0 + (u_0 v_1 + u_1 v_0) t^32
+                                       //   + u_1 v_1 t^64 = f
+
+       // Extract the high and low halves of the 192-bit result.  The answer
+       // we want is d t^128 + e t^64 + f, where e = e_0 + e_1.  The low 96
+       // bits of the answer will end up in v0, with junk in the top 32
+       // bits; the high 96 bits will end up in v1, which must have zero in
+       // its top 32 bits.
+       //
+       // Here, bot(x) is the low 96 bits of a 192-bit quantity x, arranged
+       // in the low 96 bits of a SIMD register, with junk in the top 32
+       // bits; and top(x) is the high 96 bits, also arranged in the low 96
+       // bits of a register, with /zero/ in the top 32 bits.
+       eor     v4.16b, v4.16b, v5.16b  // e_0 + e_1 = e
+       vshl128 v6, v6, 32              // top(d t^128)
+       vshr128 v5, v4, 32              // top(e t^64)
+       vshl128 v4, v4, 64              // bot(e t^64)
+       vshr128 v1, v3, 96              // top(f)
+       eor     v6.16b, v6.16b, v5.16b  // top(d t^128 + e t^64)
+       eor     v0.16b, v3.16b, v4.16b  // bot([d t^128] + e t^64 + f)
+       eor     v1.16b, v1.16b, v6.16b  // top(e t^64 + d t^128 + f)
+
+       // Finally, the reduction.  This is essentially the same as the
+       // 128-bit case, except that the polynomial is p(t) = t^96 + t^10 +
+       // t^9 + t^6 + 1.  The degrees are larger but not enough to cause
+       // trouble for the general approach.  Unfortunately, we have to do
+       // this in 32-bit pieces rather than 64.
+
+       // First, shift the high bits down.
+       ushr    v2.4s, v1.4s, #26       // the b_i for t^6
+       ushr    v3.4s, v1.4s, #23       // the b_i for t^9
+       ushr    v4.4s, v1.4s, #22       // the b_i for t^10
+       eor     v2.16b, v2.16b, v3.16b  // add them all together
+       eor     v2.16b, v2.16b, v4.16b
+       vshr128 v3, v2, 64              // contribution for high half
+       vshl128 v2, v2, 32              // contribution for low half
+       eor     v1.16b, v1.16b, v3.16b  // apply to high half
+       eor     v0.16b, v0.16b, v2.16b  // and low half
+
+       // And then shift the low bits up.
+       shl     v2.4s, v1.4s, #6
+       shl     v3.4s, v1.4s, #9
+       shl     v4.4s, v1.4s, #10
+       eor     v1.16b, v1.16b, v2.16b  // unit and t^6 contribs
+       eor     v3.16b, v3.16b, v4.16b  // t^9 and t^10 contribs
+       eor     v0.16b, v0.16b, v1.16b  // mix everything together
+       eor     v0.16b, v0.16b, v3.16b  // ... and we're done
+.endm
+
+.macro mul192
+       // Enter with u in v0 and the less-significant half of v1, with v
+       // duplicated across both halves of v2/v3/v4, and with zero in v31.
+       // Leave with the product u v in v0 and the bottom half of v1.
+       // Clobbers v16--v25.
+
+       // Start multiplying and accumulating pieces of product.
+       // v0 =                         // (u_0; u_1)
+       // v1 =                         // (u_2; ?)
+       // v2 =                         // (v_0; v_0)
+       // v3 =                         // (v_1; v_1)
+       // v4 =                         // (v_2; v_2)
+       pmull   v16.1q, v0.1d, v2.1d    //   a = u_0 v_0
+
+       pmull   v19.1q, v0.1d, v3.1d    //       u_0 v_1
+       pmull2  v21.1q, v0.2d, v2.2d    //       u_1 v_0
+
+       pmull   v17.1q, v0.1d, v4.1d    //       u_0 v_2
+       pmull2  v22.1q, v0.2d, v3.2d    //       u_1 v_1
+       pmull   v23.1q, v1.1d, v2.1d    //       u_2 v_0
+        eor    v19.16b, v19.16b, v21.16b // b = u_0 v_1 + u_1 v_0
+
+       pmull2  v20.1q, v0.2d, v4.2d    //       u_1 v_2
+       pmull   v24.1q, v1.1d, v3.1d    //       u_2 v_1
+        eor    v17.16b, v17.16b, v22.16b //     u_0 v_2 + u_1 v_1
+
+       pmull   v18.1q, v1.1d, v4.1d    //   e = u_2 v_2
+        eor    v17.16b, v17.16b, v23.16b // c = u_0 v_2 + u_1 v_1 + u_2 v_1
+        eor    v20.16b, v20.16b, v24.16b // d = u_1 v_2 + u_2 v_1
+
+       // Piece the product together.
+       // v16 =                        // (a_0; a_1)
+       // v19 =                        // (b_0; b_1)
+       // v17 =                        // (c_0; c_1)
+       // v20 =                        // (d_0; d_1)
+       // v18 =                        // (e_0; e_1)
+       vshl128 v21, v19, 64            // (0; b_0)
+       ext     v22.16b, v19.16b, v20.16b, #8 // (b_1; d_0)
+       vshr128 v23, v20, 64            // (d_1; 0)
+       eor     v16.16b, v16.16b, v21.16b // (x_0; x_1)
+       eor     v17.16b, v17.16b, v22.16b // (x_2; x_3)
+       eor     v18.16b, v18.16b, v23.16b // (x_2; x_3)
+
+       // Next, the reduction.  Our polynomial this time is p(x) = t^192 +
+       // t^7 + t^2 + t + 1.  Yes, the magic numbers are the same as the
+       // 128-bit case.  I don't know why.
+
+       // First, shift the high bits down.
+       // v16 =                        // (y_0; y_1)
+       // v17 =                        // (y_2; y_3)
+       // v18 =                        // (y_4; y_5)
+       mov     v19.d[0], v17.d[1]      // (y_3; ?)
+
+       ushr    v23.2d, v18.2d, #63     // hi b_i for t
+       ushr    d20, d19, #63           // lo b_i for t
+       ushr    v24.2d, v18.2d, #62     // hi b_i for t^2
+       ushr    d21, d19, #62           // lo b_i for t^2
+       ushr    v25.2d, v18.2d, #57     // hi b_i for t^7
+       ushr    d22, d19, #57           // lo b_i for t^7
+       eor     v23.16b, v23.16b, v24.16b // mix them all together
+       eor     v20.8b, v20.8b, v21.8b
+       eor     v23.16b, v23.16b, v25.16b
+       eor     v20.8b, v20.8b, v22.8b
+
+       // Permute the high pieces while we fold in the b_i.
+       eor     v17.16b, v17.16b, v23.16b
+       vshl128 v20, v20, 64
+       mov     v19.d[0], v18.d[1]      // (y_5; ?)
+       ext     v18.16b, v17.16b, v18.16b, #8 // (y_3; y_4)
+       eor     v16.16b, v16.16b, v20.16b
+
+       // And finally shift the low bits up.
+       // v16 =                        // (y'_0; y'_1)
+       // v17 =                        // (y'_2; ?)
+       // v18 =                        // (y'_3; y'_4)
+       // v19 =                        // (y'_5; ?)
+       shl     v20.2d, v18.2d, #1
+       shl     d23, d19, #1
+       shl     v21.2d, v18.2d, #2
+       shl     d24, d19, #2
+       shl     v22.2d, v18.2d, #7
+       shl     d25, d19, #7
+       eor     v18.16b, v18.16b, v20.16b // unit and t contribs
+       eor     v19.8b, v19.8b, v23.8b
+       eor     v21.16b, v21.16b, v22.16b // t^2 and t^7 contribs
+       eor     v24.8b, v24.8b, v25.8b
+       eor     v18.16b, v18.16b, v21.16b // all contribs
+       eor     v19.8b, v19.8b, v24.8b
+       eor     v0.16b, v16.16b, v18.16b // mix them into the low half
+       eor     v1.8b, v17.8b, v19.8b
+.endm
+
+.macro mul256
+       // Enter with u in v0/v1, with v duplicated across both halves of
+       // v2--v5, and with zero in v31.  Leave with the product u v in
+       // v0/v1.  Clobbers ???.
+
+       // Now it's starting to look worthwhile to do Karatsuba.  Suppose
+       // u = u_0 + u_1 B and v = v_0 + v_1 B.  Then
+       //
+       //      u v = (u_0 v_0) + (u_0 v_1 + u_1 v_0) B + (u_1 v_1) B^2
+       //
+       // Name these coefficients of B^i be a, b, and c, respectively, and
+       // let r = u_0 + u_1 and s = v_0 + v_1.  Then observe that
+       //
+       //      q = r s = (u_0 + u_1) (v_0 + v_1)
+       //        = (u_0 v_0) + (u1 v_1) + (u_0 v_1 + u_1 v_0)
+       //        = a + d + c
+       //
+       // The first two terms we've already calculated; the last is the
+       // remaining one we want.  We'll set B = t^128.  We know how to do
+       // 128-bit multiplications already, and Karatsuba is too annoying
+       // there, so there'll be 12 multiplications altogether, rather than
+       // the 16 we'd have if we did this the naïve way.
+       // v0 =                         // u_0 = (u_00; u_01)
+       // v1 =                         // u_1 = (u_10; u_11)
+       // v2 =                         // (v_00; v_00)
+       // v3 =                         // (v_01; v_01)
+       // v4 =                         // (v_10; v_10)
+       // v5 =                         // (v_11; v_11)
+
+       eor     v28.16b, v0.16b, v1.16b // u_* = (u_00 + u_10; u_01 + u_11)
+       eor     v29.16b, v2.16b, v4.16b // v_*0 = v_00 + v_10
+       eor     v30.16b, v3.16b, v5.16b // v_*1 = v_01 + v_11
+
+       // Start by building the cross product, q = u_* v_*.
+       pmull   v24.1q, v28.1d, v30.1d  // u_*0 v_*1
+       pmull2  v25.1q, v28.2d, v29.2d  // u_*1 v_*0
+       pmull   v20.1q, v28.1d, v29.1d  // u_*0 v_*0
+       pmull2  v21.1q, v28.2d, v30.2d  // u_*1 v_*1
+       eor     v24.16b, v24.16b, v25.16b // u_*0 v_*1 + u_*1 v_*0
+       vshr128 v25, v24, 64
+       vshl128 v24, v24, 64
+       eor     v20.16b, v20.16b, v24.16b // q_0
+       eor     v21.16b, v21.16b, v25.16b // q_1
+
+       // Next, work on the low half, a = u_0 v_0
+       pmull   v24.1q, v0.1d, v3.1d    // u_00 v_01
+       pmull2  v25.1q, v0.2d, v2.2d    // u_01 v_00
+       pmull   v16.1q, v0.1d, v2.1d    // u_00 v_00
+       pmull2  v17.1q, v0.2d, v3.2d    // u_01 v_01
+       eor     v24.16b, v24.16b, v25.16b // u_00 v_01 + u_01 v_00
+       vshr128 v25, v24, 64
+       vshl128 v24, v24, 64
+       eor     v16.16b, v16.16b, v24.16b // a_0
+       eor     v17.16b, v17.16b, v25.16b // a_1
+
+       // Mix the pieces we have so far.
+       eor     v20.16b, v20.16b, v16.16b
+       eor     v21.16b, v21.16b, v17.16b
+
+       // Finally, work on the high half, c = u_1 v_1
+       pmull   v24.1q, v1.1d, v5.1d    // u_10 v_11
+       pmull2  v25.1q, v1.2d, v4.2d    // u_11 v_10
+       pmull   v18.1q, v1.1d, v4.1d    // u_10 v_10
+       pmull2  v19.1q, v1.2d, v5.2d    // u_11 v_11
+       eor     v24.16b, v24.16b, v25.16b // u_10 v_11 + u_11 v_10
+       vshr128 v25, v24, 64
+       vshl128 v24, v24, 64
+       eor     v18.16b, v18.16b, v24.16b // c_0
+       eor     v19.16b, v19.16b, v25.16b // c_1
+
+       // Finish mixing the product together.
+       eor     v20.16b, v20.16b, v18.16b
+       eor     v21.16b, v21.16b, v19.16b
+       eor     v17.16b, v17.16b, v20.16b
+       eor     v18.16b, v18.16b, v21.16b
+
+       // Now we must reduce.  This is essentially the same as the 192-bit
+       // case above, but more complicated because everything is bigger.
+       // The polynomial this time is p(t) = t^256 + t^10 + t^5 + t^2 + 1.
+       // v16 =                        // (y_0; y_1)
+       // v17 =                        // (y_2; y_3)
+       // v18 =                        // (y_4; y_5)
+       // v19 =                        // (y_6; y_7)
+       ushr    v24.2d, v18.2d, #62     // (y_4; y_5) b_i for t^2
+       ushr    v25.2d, v19.2d, #62     // (y_6; y_7) b_i for t^2
+       ushr    v26.2d, v18.2d, #59     // (y_4; y_5) b_i for t^5
+       ushr    v27.2d, v19.2d, #59     // (y_6; y_7) b_i for t^5
+       ushr    v28.2d, v18.2d, #54     // (y_4; y_5) b_i for t^10
+       ushr    v29.2d, v19.2d, #54     // (y_6; y_7) b_i for t^10
+       eor     v24.16b, v24.16b, v26.16b // mix the contributions together
+       eor     v25.16b, v25.16b, v27.16b
+       eor     v24.16b, v24.16b, v28.16b
+       eor     v25.16b, v25.16b, v29.16b
+       vshr128 v26, v25, 64            // slide contribs into position
+       ext     v25.16b, v24.16b, v25.16b, #8
+       vshl128 v24, v24, 64
+       eor     v18.16b, v18.16b, v26.16b
+       eor     v17.16b, v17.16b, v25.16b
+       eor     v16.16b, v16.16b, v24.16b
+
+       // And then shift the low bits up.
+       // v16 =                        // (y'_0; y'_1)
+       // v17 =                        // (y'_2; y'_3)
+       // v18 =                        // (y'_4; y'_5)
+       // v19 =                        // (y'_6; y'_7)
+       shl     v24.2d, v18.2d, #2      // (y'_4; y_5) a_i for t^2
+       shl     v25.2d, v19.2d, #2      // (y_6; y_7) a_i for t^2
+       shl     v26.2d, v18.2d, #5      // (y'_4; y_5) a_i for t^5
+       shl     v27.2d, v19.2d, #5      // (y_6; y_7) a_i for t^5
+       shl     v28.2d, v18.2d, #10     // (y'_4; y_5) a_i for t^10
+       shl     v29.2d, v19.2d, #10     // (y_6; y_7) a_i for t^10
+       eor     v18.16b, v18.16b, v24.16b // mix the contributions together
+       eor     v19.16b, v19.16b, v25.16b
+       eor     v26.16b, v26.16b, v28.16b
+       eor     v27.16b, v27.16b, v29.16b
+       eor     v18.16b, v18.16b, v26.16b
+       eor     v19.16b, v19.16b, v27.16b
+       eor     v0.16b, v16.16b, v18.16b
+       eor     v1.16b, v17.16b, v19.16b
+.endm
+
+///--------------------------------------------------------------------------
+/// Main code.
+
+// There are a number of representations of field elements in this code and
+// it can be confusing.
+//
+//   * The `external format' consists of a sequence of contiguous bytes in
+//     memory called a `block'.  The GCM spec explains how to interpret this
+//     block as an element of a finite field.  As discussed extensively, this
+//     representation is very annoying for a number of reasons.  On the other
+//     hand, this code never actually deals with it directly.
+//
+//   * The `register format' consists of one or more SIMD registers,
+//     depending on the block size.  The bits in each byte are reversed,
+//     compared to the external format, which makes the polynomials
+//     completely vanilla, unlike all of the other GCM implementations.
+//
+//   * The `table format' is just like the `register format', only the two
+//     halves of 128-bit SIMD register are the same, so we need twice as many
+//     registers.
+//
+//   * The `words' format consists of a sequence of bytes, as in the
+//     `external format', but, according to the blockcipher in use, the bytes
+//     within each 32-bit word may be reversed (`big-endian') or not
+//     (`little-endian').  Accordingly, there are separate entry points for
+//     each variant, identified with `b' or `l'.
+
+FUNC(gcm_mulk_128b_arm64_pmull)
+       // On entry, x0 points to a 128-bit field element A in big-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     q0, [x0]
+       ldp     q1, q2, [x1]
+       rev32   v0.16b, v0.16b
+       vzero
+       rbit    v0.16b, v0.16b
+       mul128
+       rbit    v0.16b, v0.16b
+       rev32   v0.16b, v0.16b
+       str     q0, [x0]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_128l_arm64_pmull)
+       // On entry, x0 points to a 128-bit field element A in little-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     q0, [x0]
+       ldp     q1, q2, [x1]
+       vzero
+       rbit    v0.16b, v0.16b
+       mul128
+       rbit    v0.16b, v0.16b
+       str     q0, [x0]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_64b_arm64_pmull)
+       // On entry, x0 points to a 64-bit field element A in big-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     d0, [x0]
+       ldr     q1, [x1]
+       rev32   v0.8b, v0.8b
+       rbit    v0.8b, v0.8b
+       mul64
+       rbit    x2, x2
+       ror     x2, x2, #32
+       str     x2, [x0]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_64l_arm64_pmull)
+       // On entry, x0 points to a 64-bit field element A in little-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     d0, [x0]
+       ldr     q1, [x1]
+       rbit    v0.8b, v0.8b
+       mul64
+       rbit    x2, x2
+       rev     x2, x2
+       str     x2, [x0]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_96b_arm64_pmull)
+       // On entry, x0 points to a 96-bit field element A in big-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     w2, [x0, #8]
+       ldr     d0, [x0, #0]
+       mov     v0.d[1], x2
+       ldp     q1, q2, [x1]
+       rev32   v0.16b, v0.16b
+       vzero
+       rbit    v0.16b, v0.16b
+       mul96
+       rbit    v0.16b, v0.16b
+       rev32   v0.16b, v0.16b
+       mov     w2, v0.s[2]
+       str     d0, [x0, #0]
+       str     w2, [x0, #8]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_96l_arm64_pmull)
+       // On entry, x0 points to a 96-bit field element A in little-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     d0, [x0, #0]
+       ldr     w2, [x0, #8]
+       mov     v0.d[1], x2
+       ldp     q1, q2, [x1]
+       rbit    v0.16b, v0.16b
+       vzero
+       mul96
+       rbit    v0.16b, v0.16b
+       mov     w2, v0.s[2]
+       str     d0, [x0, #0]
+       str     w2, [x0, #8]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_192b_arm64_pmull)
+       // On entry, x0 points to a 192-bit field element A in big-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     q0, [x0, #0]
+       ldr     d1, [x0, #16]
+       ldp     q2, q3, [x1, #0]
+       ldr     q4, [x1, #32]
+       rev32   v0.16b, v0.16b
+       rev32   v1.8b, v1.8b
+       rbit    v0.16b, v0.16b
+       rbit    v1.8b, v1.8b
+       vzero
+       mul192
+       rev32   v0.16b, v0.16b
+       rev32   v1.8b, v1.8b
+       rbit    v0.16b, v0.16b
+       rbit    v1.8b, v1.8b
+       str     q0, [x0, #0]
+       str     d1, [x0, #16]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_192l_arm64_pmull)
+       // On entry, x0 points to a 192-bit field element A in little-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldr     q0, [x0, #0]
+       ldr     d1, [x0, #16]
+       ldp     q2, q3, [x1, #0]
+       ldr     q4, [x1, #32]
+       rbit    v0.16b, v0.16b
+       rbit    v1.8b, v1.8b
+       vzero
+       mul192
+       rbit    v0.16b, v0.16b
+       rbit    v1.8b, v1.8b
+       str     q0, [x0, #0]
+       str     d1, [x0, #16]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_256b_arm64_pmull)
+       // On entry, x0 points to a 256-bit field element A in big-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldp     q0, q1, [x0]
+       ldp     q2, q3, [x1, #0]
+       ldp     q4, q5, [x1, #32]
+       rev32   v0.16b, v0.16b
+       rev32   v1.16b, v1.16b
+       rbit    v0.16b, v0.16b
+       rbit    v1.16b, v1.16b
+       vzero
+       mul256
+       rev32   v0.16b, v0.16b
+       rev32   v1.16b, v1.16b
+       rbit    v0.16b, v0.16b
+       rbit    v1.16b, v1.16b
+       stp     q0, q1, [x0]
+       ret
+ENDFUNC
+
+FUNC(gcm_mulk_256l_arm64_pmull)
+       // On entry, x0 points to a 256-bit field element A in little-endian
+       // words format; x1 points to a field-element K in table format.  On
+       // exit, A is updated with the product A K.
+
+       ldp     q0, q1, [x0]
+       ldp     q2, q3, [x1, #0]
+       ldp     q4, q5, [x1, #32]
+       rbit    v0.16b, v0.16b
+       rbit    v1.16b, v1.16b
+       vzero
+       mul256
+       rbit    v0.16b, v0.16b
+       rbit    v1.16b, v1.16b
+       stp     q0, q1, [x0]
+       ret
+ENDFUNC
+
+///----- That's all, folks --------------------------------------------------
diff --git a/symm/gcm-def.h b/symm/gcm-def.h
new file mode 100644 (file)
index 0000000..34f95aa
--- /dev/null
@@ -0,0 +1,965 @@
+/* -*-c-*-
+ *
+ * The GCM authenticated encryption mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_GCM_DEF_H
+#define CATACOMB_GCM_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_BLKC_H
+#  include "blkc.h"
+#endif
+
+#ifndef CATACOMB_CT_H
+#  include "ct.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+#  include "keysz.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef struct gcm_params {
+  unsigned f;                          /* flags */
+#define GCMF_SWAP 1u                   /*   swap byte order? */
+  unsigned n;                          /* number of words in block */
+  uint32 poly;                         /* selected polynomial mask */
+} gcm_params;
+
+/*----- Utilities ---------------------------------------------------------*/
+
+/* Supported block sizes. */
+#define GCM_WIDTHS(_) _(64) _(96) _(128) _(192) _(256)
+#define GCM_NMAX 8
+
+/* Polynomial tails for the supported block sizes. */
+#define GCM_POLY_64  0xd8000000
+#define GCM_POLY_96  0x82600000
+#define GCM_POLY_128 0xe1000000
+#define GCM_POLY_192 0xe1000000
+#define GCM_POLY_256 0xa4200000
+
+/* Determine whether to set the @GCMF_SWAP@ flag. */
+#define GCM_SWAP_L GCMF_SWAP
+#define GCM_SWAP_B 0
+
+/* --- @gcm_mktable@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *ktab@ = where to write the table; there must be
+ *                     space for %$32 n$% $%n$%-word entries, i.e.,
+ *                     %$32 n^2$% 32-bit words in total, where %$n$% is
+ *                     @p->n@, the block size in words
+ *             @const uint32 *k@ = input field element
+ *
+ * Returns:    ---
+ *
+ * Use:                Construct a table for use by @gcm_mulk_...@ below, to
+ *             multiply (vaguely) efficiently by @k@.
+ */
+
+extern void gcm_mktable(const gcm_params */*p*/,
+                       uint32 */*ktab*/, const uint32 */*k*/);
+
+/* --- @gcm_mulk_N{b,l}@ --- *
+ *
+ * Arguments:  @uint32 *a@ = accumulator to multiply
+ *             @const uint32 *ktab@ = table constructed by @gcm_mktable@
+ *
+ * Returns:    ---
+ *
+ * Use:                Multiply @a@ by @k@ (implicitly represented in @ktab@),
+ *             updating @a@ in-place.  There are separate functions for each
+ *             supported block size and endianness because this is the
+ *             function whose performance actually matters.
+ */
+
+#define GCM_DECL_MULK(nbits)                                           \
+  extern void gcm_mulk_##nbits##b(uint32 */*a*/, const uint32 */*ktab*/); \
+  extern void gcm_mulk_##nbits##l(uint32 */*a*/, const uint32 */*ktab*/);
+GCM_WIDTHS(GCM_DECL_MULK)
+#undef GCM_DECL_MULK
+
+/* Dispatch to the appropriate variant of @gcm_mulk@. */
+#define GCM_MULK(PRE, a, ktab)                                         \
+  BLKC_GLUE(GCM_MULK_, BLKC_ENDIAN(PRE))(BLKC_BITS(PRE), a, ktab)
+#define GCM_MULK_B(nbits, a, ktab)                                     \
+  BLKC_GLUE(BLKC_GLUE(gcm_mulk_, nbits), b)(a, ktab)
+#define GCM_MULK_L(nbits, a, ktab)                                     \
+  BLKC_GLUE(BLKC_GLUE(gcm_mulk_, nbits), l)(a, ktab)
+
+/* --- @gcm_ghashdone@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *a@ = GHASH accumulator
+ *             @const uint32 *ktab@ = multiplication table, built by
+ *                     @gcm_mktable@
+ *             @unsigned long xblocks, yblocks@ = number of whole blocks in
+ *                     the two inputs
+ *             @unsigned xbytes, ybytes@ = number of trailing bytes in the
+ *                     two inputs
+ *
+ * Returns:    ---
+ *
+ * Use:                Finishes a GHASH operation by appending the appropriately
+ *             encoded lengths of the two constituent messages.
+ */
+
+extern void gcm_ghashdone(const gcm_params */*p*/,
+                         uint32 */*a*/, const uint32 */*ktab*/,
+                         unsigned long /*xblocks*/, unsigned /*xbytes*/,
+                         unsigned long /*yblocks*/, unsigned /*ybytes*/);
+
+/* --- @gcm_concat@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *z@ = GHASH accumulator for suffix, updated
+ *             @const uint32 *x@ = GHASH accumulator for prefix
+ *             @const uint32 *ktab@ = multiplication table, built by
+ *                     @gcm_mktable@
+ *             @unsigned long n@ = length of suffix in whole blocks
+ *
+ * Returns:    ---
+ *
+ * Use:                On entry, @x@ and @z@ are the results of hashing two strings
+ *             %$a$% and %$b$%, each a whole number of blocks long; in
+ *             particular, %$b$% is @n@ blocks long.  On exit, @z@ is
+ *             updated to be the hash of %$a \cat b$%.
+ */
+
+extern void gcm_concat(const gcm_params */*p*/,
+                      uint32 */*z*/, const uint32 */*x*/,
+                      const uint32 */*ktab*/, unsigned long /*n*/);
+
+/* Step the counter using GCM's strange only-the-last-32-bits convention. */
+#define GCM_STEP(PRE, w) BLKC_GLUE(GCM_STEP_, BLKC_ENDIAN(PRE))(PRE, w)
+#define GCM_STEP_B(PRE, w) GCM_STEP_X(PRE, BLKC_ID, w)
+#define GCM_STEP_L(PRE, w) GCM_STEP_X(PRE, ENDSWAP32, w)
+#define GCM_STEP_X(PRE, op, w) do {                                    \
+  BLKC_W(w);                                                           \
+  _w[PRE##_BLKSZ/4 - 1] = op(op(_w[PRE##_BLKSZ/4 - 1]) + 1);           \
+} while (0)
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @GCM_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates an implementation for the GCM authenticated-
+ *             encryption mode.
+ */
+
+#define GCM_DEF(PRE, pre) GCM_DEFX(PRE, pre, #pre, #pre)
+
+#define GCM_DEFX(PRE, pre, name, fname)                                        \
+                                                                       \
+static const gcm_params pre##_gcmparams = {                            \
+  BLKC_GLUE(GCM_SWAP_, BLKC_ENDIAN(PRE)),                              \
+  PRE##_BLKSZ/4,                                                       \
+  BLKC_GLUE(GCM_POLY_, BLKC_BITS(PRE))                                 \
+};                                                                     \
+                                                                       \
+const octet                                                            \
+  pre##_gcmnoncesz[] = { KSZ_ANY, PRE##_BLKSZ - 4 },                   \
+  pre##_gcmtagsz[] = { KSZ_RANGE, PRE##_BLKSZ, 0, PRE##_BLKSZ, 1 };    \
+                                                                       \
+static const rsvr_policy pre##_gcmpolicy = { 0, PRE##_BLKSZ, PRE##_BLKSZ }; \
+                                                                       \
+/* --- @pre_gcmsetkey@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_gcmkey *key@ = pointer to key block to fill in     \
+ *             @const void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an GCM key block.                           \
+ */                                                                    \
+                                                                       \
+void pre##_gcmsetkey(pre##_gcmkey *key, const void *k, size_t ksz)     \
+{                                                                      \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+                                                                       \
+  /* Initialize the block cipher. */                                   \
+  pre##_init(&key->ctx, k, ksz);                                       \
+                                                                       \
+  /* Set up the GHASH multiplication table. */                         \
+  BLKC_ZERO(PRE, t); pre##_eblk(&key->ctx, t, t);                      \
+  gcm_mktable(&pre##_gcmparams, key->ktab, t);                         \
+}                                                                      \
+                                                                       \
+/* --- @pre_gcmaadinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmaadctx *aad@ = pointer to AAD context           \
+ *             @const pre_gcmkey *key@ = pointer to key block          \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an GCM AAD (`additional authenticated       \
+ *             data') context associated with a given key.  AAD        \
+ *             contexts can be copied and/or reused, saving time if    \
+ *             the AAD for a number of messages has a common prefix.   \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around, though        \
+ *             usually there'll at least be another copy in some GCM   \
+ *             operation context because the AAD on its own isn't much \
+ *             good.                                                   \
+ */                                                                    \
+                                                                       \
+void pre##_gcmaadinit(pre##_gcmaadctx *aad, const pre##_gcmkey *key)   \
+  { aad->k = *key; aad->off = 0; aad->len = 0; BLKC_ZERO(PRE, aad->a); } \
+                                                                       \
+/* --- @pre_gcmaadhash@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmaadctx *aad@ = pointer to AAD context           \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.                             \
+ */                                                                    \
+                                                                       \
+void pre##_gcmaadhash(pre##_gcmaadctx *aad, const void *p, size_t sz)  \
+{                                                                      \
+  rsvr_state st;                                                       \
+  const octet *q;                                                      \
+                                                                       \
+  rsvr_setup(&st, &pre##_gcmpolicy, aad->b, &aad->off, p, sz);         \
+  RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    BLKC_XLOAD(PRE, aad->a, q); GCM_MULK(PRE, aad->a, aad->k.ktab);    \
+    aad->len++;                                                                \
+  }                                                                    \
+}                                                                      \
+                                                                       \
+/* --- @pre_gcminit@ --- *                                             \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM context              \
+ *             @const pre_gcmkey *key@ = pointer to key block          \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initialize an GCM operation context with a given key.   \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+void pre##_gcminit(pre##_gcmctx *ctx, const pre##_gcmkey *k,           \
+                  const void *n, size_t nsz)                           \
+  { ctx->k = *k; pre##_gcmreinit(ctx, n, nsz); }                       \
+                                                                       \
+/* --- @pre_gcmreinit@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM context              \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Reinitialize an GCM operation context, changing the     \
+ *             nonce.                                                  \
+ */                                                                    \
+                                                                       \
+void pre##_gcmreinit(pre##_gcmctx *ctx, const void *n, size_t nsz)     \
+{                                                                      \
+  octet b[PRE##_BLKSZ];                                                        \
+  const octet *q = n;                                                  \
+  size_t nblocks;                                                      \
+  unsigned i;                                                          \
+                                                                       \
+  /* Zero the counters. */                                             \
+  ctx->off = 0; ctx->len = 0;                                          \
+  BLKC_ZERO(PRE, ctx->a);                                              \
+                                                                       \
+  /* Calculate the initial counter from the nonce. */                  \
+  if (nsz == PRE##_BLKSZ - 4) {                                                \
+    /* Easy version: initialize the final word to 1 and copy the       \
+     * remaining words from the nonce.  (The spec shows the nonce and  \
+     * counter the other way around for 64-bit block ciphers, but I'm  \
+     * sure this is just a mistake.)                                   \
+     */                                                                        \
+                                                                       \
+    for (i = 0; i < PRE##_BLKSZ/4 - 1; i++)                            \
+      { ctx->c0[i] = BLKC_LOAD_E(PRE)(q); q += 4; }                    \
+    ctx->c0[PRE##_BLKSZ/4 - 1] = BLKC_BWORD(PRE, 1);                   \
+  } else {                                                             \
+    /* Harder version: hash the nonce down with GHASH. */              \
+                                                                       \
+    BLKC_ZERO(PRE, ctx->c0); nblocks = 0;                              \
+    while (nsz >= PRE##_BLKSZ) {                                       \
+      BLKC_XLOAD(PRE, ctx->c0, q); q += PRE##_BLKSZ;                   \
+      GCM_MULK(PRE, ctx->c0, ctx->k.ktab);                             \
+      nsz -= PRE##_BLKSZ; nblocks++;                                   \
+    }                                                                  \
+    if (nsz) {                                                         \
+      memcpy(b, q, nsz); memset(b + nsz, 0, PRE##_BLKSZ - nsz);                \
+      BLKC_XLOAD(PRE, ctx->c0, b);                                     \
+      GCM_MULK(PRE, ctx->c0, ctx->k.ktab);                             \
+    }                                                                  \
+    gcm_ghashdone(&pre##_gcmparams, ctx->c0, ctx->k.ktab,              \
+                 0, 0, nblocks, nsz);                                  \
+  }                                                                    \
+                                                                       \
+  /* We must remember the initial counter for the final tag            \
+   * calculation.  (I conjecture that storing the final counter instead        \
+   * would be just as secure, and require less state, but I've not     \
+   * proven this, and anyway it wouldn't interoperate.)  Copy it to    \
+   * make the working counter.                                         \
+   */                                                                  \
+  BLKC_MOVE(PRE, ctx->c, ctx->c0);                                     \
+}                                                                      \
+                                                                       \
+/* --- @pre_gcmencrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM operation context    \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For GCM, we always write a ciphertext chunk the same    \
+ *             size as the plaintext.  The messing about with @buf@    \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+int pre##_gcmencrypt(pre##_gcmctx *ctx,                                        \
+                    const void *src, size_t sz, buf *dst)              \
+{                                                                      \
+  rsvr_plan plan;                                                      \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *p = src;                                                        \
+  octet *q, *r, y;                                                     \
+                                                                       \
+  /* Allocate space for the ciphertext. */                             \
+  if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+                                                                       \
+  /* Determine the buffering plan.  Our buffer is going to do double-  \
+   * duty here.  The end portion is going to contain mask from the     \
+   * encrypted counter which we mix into the plaintext to encrypt it;  \
+   * the start portion, which originally mask bytes we've already used,        \
+   * will hold the output ciphertext, which will eventually be         \
+   * collected into the GHASH state.                                   \
+   */                                                                  \
+  rsvr_mkplan(&plan, &pre##_gcmpolicy, ctx->off, sz);                  \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the buffer is     \
+   * empty, then that means that we haven't yet encrypted the current  \
+   * counter, so we should do that and advance it.                     \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      GCM_STEP(PRE, ctx->c); pre##_eblk(&ctx->k.ctx, ctx->c, t);       \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
+    }                                                                  \
+    r = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    while (plan.head--) { y = *p++ ^ *r; *r++ = *q++ = y; }            \
+  }                                                                    \
+                                                                       \
+  /* If we've filled up the buffer then we need to cycle the MAC and   \
+   * reset the offset.                                                 \
+   */                                                                  \
+  if (plan.from_rsvr) {                                                        \
+    BLKC_XLOAD(PRE, ctx->a, ctx->b); GCM_MULK(PRE, ctx->a, ctx->k.ktab); \
+    ctx->len++; ctx->off = 0;                                          \
+  }                                                                    \
+                                                                       \
+  /* Now to process the main body of the input. */                     \
+  while (plan.from_input) {                                            \
+    GCM_STEP(PRE, ctx->c); pre##_eblk(&ctx->k.ctx, ctx->c, t);         \
+    BLKC_XLOAD(PRE, t, p); p += PRE##_BLKSZ;                           \
+    BLKC_STORE(PRE, q, t); q += PRE##_BLKSZ;                           \
+    BLKC_XMOVE(PRE, ctx->a, t); GCM_MULK(PRE, ctx->a, ctx->k.ktab);    \
+    plan.from_input -= PRE##_BLKSZ; ctx->len++;                                \
+  }                                                                    \
+                                                                       \
+  /* Finally, deal with any final portion.  If there is one, we know   \
+   * that the buffer is empty: we must have filled it above, or this   \
+   * would all count as `initial' data.                                        \
+   */                                                                  \
+  if (plan.tail) {                                                     \
+    GCM_STEP(PRE, ctx->c); pre##_eblk(&ctx->k.ctx, ctx->c, t);         \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    r = ctx->b; ctx->off += plan.tail;                                 \
+    while (plan.tail--) { y = *p++ ^ *r; *r++ = *q++ = y; }            \
+  }                                                                    \
+                                                                       \
+  /* And we're done. */                                                        \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_gcmdecrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM operation context    \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For GCM, we always write a plaintext chunk the same     \
+ *             size as the ciphertext.  The messing about with @buf@   \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+int pre##_gcmdecrypt(pre##_gcmctx *ctx,                                        \
+                    const void *src, size_t sz, buf *dst)              \
+{                                                                      \
+  rsvr_plan plan;                                                      \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ];                             \
+  const octet *p = src;                                                        \
+  octet *q, *r, y;                                                     \
+                                                                       \
+  /* Allocate space for the plaintext. */                              \
+  if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+                                                                       \
+  /* Determine the buffering plan.  Our buffer is going to do double-  \
+   * duty here.  The end portion is going to contain mask from the     \
+   * encrypted counter which we mix into the plaintext to encrypt it;  \
+   * the start portion, which originally mask bytes we've already used,        \
+   * will hold the input ciphertext, which will eventually be          \
+   * collected into the GHASH state.                                   \
+   */                                                                  \
+  rsvr_mkplan(&plan, &pre##_gcmpolicy, ctx->off, sz);                  \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the buffer is     \
+   * empty, then that means that we haven't yet encrypted the current  \
+   * counter, so we should do that and advance it.                     \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      GCM_STEP(PRE, ctx->c); pre##_eblk(&ctx->k.ctx, ctx->c, t);       \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
+    }                                                                  \
+    r = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    while (plan.head--) { y = *p++; *q++ = y ^ *r; *r++ = y; }         \
+  }                                                                    \
+                                                                       \
+  /* If we've filled up the buffer then we need to cycle the MAC and   \
+   * reset the offset.                                                 \
+   */                                                                  \
+  if (plan.from_rsvr) {                                                        \
+    BLKC_XLOAD(PRE, ctx->a, ctx->b); GCM_MULK(PRE, ctx->a, ctx->k.ktab); \
+    ctx->len++; ctx->off = 0;                                          \
+  }                                                                    \
+                                                                       \
+  /* Now to process the main body of the input. */                     \
+  while (plan.from_input) {                                            \
+    GCM_STEP(PRE, ctx->c); pre##_eblk(&ctx->k.ctx, ctx->c, t);         \
+    BLKC_LOAD(PRE, u, p); p += PRE##_BLKSZ;                            \
+    BLKC_XSTORE(PRE, q, t, u); q += PRE##_BLKSZ;                       \
+    BLKC_XMOVE(PRE, ctx->a, u); GCM_MULK(PRE, ctx->a, ctx->k.ktab);    \
+    plan.from_input -= PRE##_BLKSZ; ctx->len++;                                \
+  }                                                                    \
+                                                                       \
+  /* Finally, deal with any final portion.  If there is one, we know   \
+   * that the buffer is empty: we must have filled it above, or this   \
+   * would all count as `initial' data.                                        \
+   */                                                                  \
+  if (plan.tail) {                                                     \
+    GCM_STEP(PRE, ctx->c); pre##_eblk(&ctx->k.ctx, ctx->c, t);         \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    r = ctx->b; ctx->off += plan.tail;                                 \
+    while (plan.tail--) { y = *p++; *q++ = y ^ *r; *r++ = y; }         \
+  }                                                                    \
+                                                                       \
+  /* And we're done. */                                                        \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_gcmtag@ --- *                                              \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to an GCM context           \
+ *             @const pre_gcmaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @octet *t@ = where to write a (full-length) tag         \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes an GCM operation, by calculating the tag.      \
+ */                                                                    \
+                                                                       \
+static void pre##_gcmtag(pre##_gcmctx *ctx,                            \
+                        const pre##_gcmaadctx *aad, octet *t)          \
+{                                                                      \
+  octet b[PRE##_BLKSZ];                                                        \
+  uint32 u[PRE##_BLKSZ/4];                                             \
+  unsigned long n;                                                     \
+                                                                       \
+  /* Finish tagging the ciphertext. */                                 \
+  if (ctx->off) {                                                      \
+    memcpy(b, ctx->b, ctx->off);                                       \
+    memset(b + ctx->off, 0, PRE##_BLKSZ - ctx->off);                   \
+    BLKC_XLOAD(PRE, ctx->a, b); GCM_MULK(PRE, ctx->a, ctx->k.ktab);    \
+  }                                                                    \
+                                                                       \
+  /* If there's no AAD, because the pointer is null or no data was     \
+   * supplied, then apply that to the GHASH state.  (Otherwise there's \
+   * nothing to do here.)                                              \
+   */                                                                  \
+  if (aad && (aad->len || aad->off)) {                                 \
+    BLKC_MOVE(PRE, u, aad->a);                                         \
+    if (aad->off) {                                                    \
+      memcpy(b, aad->b, aad->off);                                     \
+      memset(b + aad->off, 0, PRE##_BLKSZ - aad->off);                 \
+      BLKC_XLOAD(PRE, u, b); GCM_MULK(PRE, u, ctx->k.ktab);            \
+    }                                                                  \
+    n = ctx->len; if (ctx->off) n++;                                   \
+    gcm_concat(&pre##_gcmparams, ctx->a, u, ctx->k.ktab, n);           \
+  }                                                                    \
+                                                                       \
+  /* Finish off the hash by appending the length. */                   \
+  gcm_ghashdone(&pre##_gcmparams, ctx->a, ctx->k.ktab,                 \
+               aad ? aad->len : 0, aad ? aad->off : 0,                 \
+               ctx->len, ctx->off);                                    \
+                                                                       \
+  /* Mask the hash and store. */                                       \
+  pre##_eblk(&ctx->k.ctx, ctx->c0, u);                                 \
+  BLKC_XSTORE(PRE, t, ctx->a, u);                                      \
+}                                                                      \
+                                                                       \
+/* --- @pre_gcmencryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to an GCM context           \
+ *             @const pre_gcmaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an GCM encryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  GCM doesn't buffer ciphertext, but \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+int pre##_gcmencryptdone(pre##_gcmctx *ctx,                            \
+                        const pre##_gcmaadctx *aad, buf *dst,          \
+                        void *tag, size_t tsz)                         \
+{                                                                      \
+  octet t[PRE##_BLKSZ];                                                        \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  if (!BOK(dst)) return (-1);                                          \
+  pre##_gcmtag(ctx, aad, t); memcpy(tag, t, tsz);                      \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_gcmdecryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to an GCM context           \
+ *             @const pre_gcmaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an GCM decryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  GCM doesn't buffer plaintext, but  \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+int pre##_gcmdecryptdone(pre##_gcmctx *ctx,                            \
+                        const pre##_gcmaadctx *aad, buf *dst,          \
+                        const void *tag, size_t tsz)                   \
+{                                                                      \
+  octet t[PRE##_BLKSZ];                                                        \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  if (!BOK(dst)) return (-1);                                          \
+  pre##_gcmtag(ctx, aad, t);                                           \
+  if (!ct_memeq(tag, t, tsz)) return (0);                              \
+  else return (+1);                                                    \
+}                                                                      \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+typedef struct gactx {                                                 \
+  gaead_aad a;                                                         \
+  pre##_gcmaadctx aad;                                                 \
+} gactx;                                                               \
+                                                                       \
+static gaead_aad *gadup(const gaead_aad *a)                            \
+  { gactx *aad = S_CREATE(gactx); *aad = *(gactx *)a; return (&aad->a); } \
+                                                                       \
+static void gahash(gaead_aad *a, const void *h, size_t hsz)            \
+  { gactx *aad = (gactx *)a; pre##_gcmaadhash(&aad->aad, h, hsz); }    \
+                                                                       \
+static void gadestroy(gaead_aad *a)                                    \
+  { gactx *aad = (gactx *)a; BURN(*aad); S_DESTROY(aad); }             \
+                                                                       \
+static const gaead_aadops gaops =                                      \
+  { &pre##_gcm, gadup, gahash, gadestroy };                            \
+                                                                       \
+static gaead_aad *gaad(const pre##_gcmkey *k)                          \
+{                                                                      \
+  gactx *aad = S_CREATE(gactx);                                                \
+  aad->a.ops = &gaops;                                                 \
+  pre##_gcmaadinit(&aad->aad, k);                                      \
+  return (&aad->a);                                                    \
+}                                                                      \
+                                                                       \
+typedef struct gectx {                                                 \
+  gaead_enc e;                                                         \
+  pre##_gcmctx ctx;                                                    \
+} gectx;                                                               \
+                                                                       \
+static gaead_aad *geaad(gaead_enc *e)                                  \
+  { gectx *enc = (gectx *)e; return (gaad(&enc->ctx.k)); }             \
+                                                                       \
+static int gereinit(gaead_enc *e, const void *n, size_t nsz,           \
+                   size_t hsz, size_t msz, size_t tsz)                 \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  pre##_gcmreinit(&enc->ctx, n, nsz);                                  \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int geenc(gaead_enc *e, const void *m, size_t msz, buf *b)      \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_gcmencrypt(&enc->ctx, m, msz, b));                     \
+}                                                                      \
+                                                                       \
+static int gedone(gaead_enc *e, const gaead_aad *a,                    \
+                 buf *b, void *t, size_t tsz)                          \
+{                                                                      \
+  gectx *enc = (gectx *)e; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_gcmencryptdone(&enc->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gedestroy(gaead_enc *e)                                    \
+  { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); }             \
+                                                                       \
+static const gaead_encops geops =                                      \
+  { &pre##_gcm, geaad, gereinit, geenc, gedone, gedestroy };           \
+                                                                       \
+typedef struct gdctx {                                                 \
+  gaead_dec d;                                                         \
+  pre##_gcmctx ctx;                                                    \
+} gdctx;                                                               \
+                                                                       \
+static gaead_aad *gdaad(gaead_dec *d)                                  \
+  { gdctx *dec = (gdctx *)d; return (gaad(&dec->ctx.k)); }             \
+                                                                       \
+static int gdreinit(gaead_dec *d, const void *n, size_t nsz,           \
+                    size_t hsz, size_t csz, size_t tsz)                \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+                                                                       \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+  pre##_gcmreinit(&dec->ctx, n, nsz);                                  \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int gddec(gaead_dec *d, const void *c, size_t csz, buf *b)      \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_gcmdecrypt(&dec->ctx, c, csz, b));                     \
+}                                                                      \
+                                                                       \
+static int gddone(gaead_dec *d, const gaead_aad *a,                    \
+                 buf *b, const void *t, size_t tsz)                    \
+{                                                                      \
+  gdctx *dec = (gdctx *)d; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_gcmdecryptdone(&dec->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gddestroy(gaead_dec *d)                                    \
+  { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); }             \
+                                                                       \
+static const gaead_decops gdops =                                      \
+  { &pre##_gcm, gdaad, gdreinit, gddec, gddone, gddestroy };           \
+                                                                       \
+typedef struct gkctx {                                                 \
+  gaead_key k;                                                         \
+  pre##_gcmkey key;                                                    \
+} gkctx;                                                               \
+                                                                       \
+static gaead_aad *gkaad(const gaead_key *k)                            \
+  { gkctx *key = (gkctx *)k; return (gaad(&key->key)); }               \
+                                                                       \
+static gaead_enc *gkenc(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t msz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gectx *enc = S_CREATE(gectx);                                                \
+                                                                       \
+  enc->e.ops = &geops;                                                 \
+  pre##_gcminit(&enc->ctx, &key->key, n, nsz);                         \
+  return (&enc->e);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_dec *gkdec(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t csz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gdctx *dec = S_CREATE(gdctx);                                                \
+                                                                       \
+  dec->d.ops = &gdops;                                                 \
+  pre##_gcminit(&dec->ctx, &key->key, n, nsz);                         \
+  return (&dec->d);                                                    \
+}                                                                      \
+                                                                       \
+static void gkdestroy(gaead_key *k)                                    \
+  { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); }             \
+                                                                       \
+static const gaead_keyops gkops =                                      \
+  { &pre##_gcm, gkaad, gkenc, gkdec, gkdestroy };                      \
+                                                                       \
+static gaead_key *gckey(const void *k, size_t ksz)                     \
+{                                                                      \
+  gkctx *key = S_CREATE(gkctx);                                                \
+  key->k.ops = &gkops;                                                 \
+  pre##_gcmsetkey(&key->key, k, ksz);                                  \
+  return (&key->k);                                                    \
+}                                                                      \
+                                                                       \
+const gcaead pre##_gcm = {                                             \
+  name "-gcm",                                                         \
+  pre##_keysz, pre##_gcmnoncesz, pre##_gcmtagsz,                       \
+  PRE##_BLKSZ, 0, 0, 0,                                                        \
+  gckey                                                                        \
+};                                                                     \
+                                                                       \
+GCM_TESTX(PRE, pre, name, fname)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#define GCM_TEST(PRE, pre) GCM_TESTX(PRE, pre, #pre, #pre)
+
+/* --- @GCM_TEST@ --- *
+ *
+ * Arguments:  @PRE, pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Standard test rig for GCM functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define GCM_TESTX(PRE, pre, name, fname)                               \
+                                                                       \
+static int gcmverify(dstr *v)                                          \
+{                                                                      \
+  pre##_gcmkey key;                                                    \
+  pre##_gcmaadctx aad;                                                 \
+  pre##_gcmctx ctx;                                                    \
+  int ok = 1, win;                                                     \
+  int i;                                                               \
+  octet *p;                                                            \
+  int szs[] = { 1, 7, 192, -1, 0 }, *ip;                               \
+  size_t hsz, msz;                                                     \
+  dstr d = DSTR_INIT, t = DSTR_INIT;                                   \
+  buf b;                                                               \
+                                                                       \
+  dstr_ensure(&d, v[4].len > v[3].len ? v[4].len : v[3].len);          \
+  dstr_ensure(&t, v[5].len); t.len = v[5].len;                         \
+                                                                       \
+  pre##_gcmsetkey(&key, v[0].buf, v[0].len);                           \
+                                                                       \
+  for (ip = szs; *ip; ip++) {                                          \
+                                                                       \
+    pre##_gcminit(&ctx, &key, (octet *)v[1].buf, v[1].len);            \
+                                                                       \
+    i = *ip;                                                           \
+    hsz = v[2].len;                                                    \
+    if (i == -1) i = hsz;                                              \
+    if (i > hsz) continue;                                             \
+    p = (octet *)v[2].buf;                                             \
+    pre##_gcmaadinit(&aad, &key);                                      \
+    while (hsz) {                                                      \
+      if (i > hsz) i = hsz;                                            \
+      pre##_gcmaadhash(&aad, p, i);                                    \
+      p += i; hsz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[3].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[3].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_gcmencrypt(&ctx, p, i, &b)) {                          \
+       puts("!! gcmencrypt reports failure");                          \
+       goto fail_enc;                                                  \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    if (pre##_gcmencryptdone(&ctx, &aad, &b, (octet *)t.buf, t.len)) { \
+      puts("!! gcmencryptdone reports failure");                       \
+      goto fail_enc;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[4].len ||                                           \
+       memcmp(d.buf, v[4].buf, v[4].len) != 0 ||                       \
+       memcmp(t.buf, v[5].buf, v[5].len) != 0) {                       \
+    fail_enc:                                                          \
+      printf("\nfail encrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tmessage = ", stdout); type_hex.dump(&v[3], stdout);   \
+      fputs("\n\texp ct = ", stdout); type_hex.dump(&v[4], stdout);    \
+      fputs("\n\tcalc ct = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\texp tag = ", stdout); type_hex.dump(&v[5], stdout);   \
+      fputs("\n\tcalc tag = ", stdout); type_hex.dump(&t, stdout);     \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+                                                                       \
+    pre##_gcminit(&ctx, &key, (octet *)v[1].buf, v[1].len);            \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[4].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[4].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_gcmdecrypt(&ctx, p, i, &b)) {                          \
+       puts("!! gcmdecrypt reports failure");                          \
+       win = 0; goto fail_dec;                                         \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    win = pre##_gcmdecryptdone(&ctx, &aad, &b,                         \
+                              (octet *)v[5].buf, v[5].len);            \
+    if (win < 0) {                                                     \
+      puts("!! gcmdecryptdone reports failure");                       \
+      goto fail_dec;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[3].len || !win ||                                   \
+       memcmp(d.buf, v[3].buf, v[3].len) != 0) {                       \
+    fail_dec:                                                          \
+      printf("\nfail decrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tciphertext = ", stdout); type_hex.dump(&v[4], stdout);        \
+      fputs("\n\texp pt = ", stdout); type_hex.dump(&v[3], stdout);    \
+      fputs("\n\tcalc pt = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\ttag = ", stdout); type_hex.dump(&v[5], stdout);       \
+      printf("\n\tverify %s", win ? "ok" : "FAILED");                  \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  dstr_destroy(&d); dstr_destroy(&t);                                  \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static test_chunk aeaddefs[] = {                                       \
+  { name "-gcm", gcmverify,                                            \
+    { &type_hex, &type_hex, &type_hex, &type_hex,                      \
+      &type_hex, &type_hex, 0 } },                                     \
+  { 0, 0, { 0 } }                                                      \
+};                                                                     \
+                                                                       \
+int main(int argc, char *argv[])                                       \
+{                                                                      \
+  ego(argv[0]);                                                                \
+  test_run(argc, argv, aeaddefs, SRCDIR"/t/" fname);                   \
+  return (0);                                                          \
+}
+
+#else
+#  define GCM_TESTX(PRE, pre, name, fname)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/gcm-x86ish-pclmul.S b/symm/gcm-x86ish-pclmul.S
new file mode 100644 (file)
index 0000000..e60b7ca
--- /dev/null
@@ -0,0 +1,1073 @@
+/// -*- mode: asm; asm-comment-char: ?/ -*-
+///
+/// GCM acceleration for x86 processors
+///
+/// (c) 2018 Straylight/Edgeware
+///
+
+///----- Licensing notice ---------------------------------------------------
+///
+/// This file is part of Catacomb.
+///
+/// Catacomb is free software: you can redistribute it and/or modify it
+/// under the terms of the GNU Library General Public License as published
+/// by the Free Software Foundation; either version 2 of the License, or
+/// (at your option) any later version.
+///
+/// Catacomb is distributed in the hope that it will be useful, but
+/// WITHOUT ANY WARRANTY; without even the implied warranty of
+/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+/// Library General Public License for more details.
+///
+/// You should have received a copy of the GNU Library General Public
+/// License along with Catacomb.  If not, write to the Free Software
+/// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+/// USA.
+
+///--------------------------------------------------------------------------
+/// Preliminaries.
+
+#include "config.h"
+#include "asm-common.h"
+
+       .arch   .pclmul
+
+       .text
+
+///--------------------------------------------------------------------------
+/// Common register allocation.
+
+#if CPUFAM_X86
+#  define A eax
+#  define K edx
+#elif CPUFAM_AMD64 && ABI_SYSV
+#  define A rdi
+#  define K rsi
+#elif CPUFAM_AMD64 && ABI_WIN
+#  define A rcx
+#  define K rdx
+#endif
+
+///--------------------------------------------------------------------------
+/// Multiplication macros.
+
+       // The good news is that we have a fancy instruction to do the
+       // multiplications.  The bad news is that it's not particularly well-
+       // suited to the job.
+       //
+       // For one thing, it only does a 64-bit multiplication, so in general
+       // we'll need to synthesize the full-width multiply by hand.  For
+       // another thing, it doesn't help with the reduction, so we have to
+       // do that by hand too.  And, finally, GCM has crazy bit ordering,
+       // and the instruction does nothing useful for that at all.
+       //
+       // Focusing on that last problem first: the bits aren't in monotonic
+       // significance order unless we permute them.  If we reverse the byte
+       // order, then we'll have the bits in monotonic order, but backwards,
+       // so the degree-0 coefficient will be in the most-significant bit.
+       //
+       // This is less of a difficulty than it seems at first, because
+       // algebra.  Suppose we are given u = SUM_{0<=i<n} u_i t^i and v =
+       // SUM_{0<=j<n} v_j t^j; then
+       //
+       //      u v = SUM_{0<=i,j<n} u_i v_j t^{i+j}
+       //
+       // Suppose instead that we're given ũ = SUM_{0<=i<n} u_{n-i-1} t^i
+       // and ṽ = SUM_{0<=j<n} v_{n-j-1} t^j, so the bits are backwards.
+       // Then
+       //
+       //      ũ ṽ = SUM_{0<=i,j<n} u_{n-i-1} v_{n-j-1} t^{i+j}
+       //          = SUM_{0<=i,j<n} u_i v_j t^{2n-2-(i+j)}
+       //
+       // which is almost the bit-reversal of u v, only it's shifted right
+       // by one place.  Oh, well: we'll have to shift it back later.
+       //
+       // That was important to think about, but there's not a great deal to
+       // do about it yet other than to convert what we've got from the
+       // blockcipher's byte-ordering convention to our big-endian
+       // convention.  Since this depends on the blockcipher convention,
+       // we'll leave the caller to cope with this: the macros here will
+       // assume that the operands are in `register' format, which is the
+       // byte-reversal of the external representation, padded at the
+       // most-significant end except for 96-bit blocks, which are
+       // zero-padded at the least-significant end (see `mul96' for the
+       // details).  In the commentary, pieces of polynomial are numbered
+       // according to the degree of the coefficients, so the unit
+       // coefficient of some polynomial a is in a_0.
+       //
+       // The commentary for `mul128' is the most detailed.  The other
+       // macros assume that you've already read and understood that.
+
+.macro mul128
+       // Enter with u and v in xmm0 and xmm1 respectively; leave with z =
+       // u v in xmm0.  Clobbers xmm1--xmm4.
+
+       // First for the double-precision multiplication.  It's tempting to
+       // use Karatsuba's identity here, but I suspect that loses more in
+       // the shifting, bit-twiddling, and dependency chains that it gains
+       // in saving a multiplication which otherwise pipelines well.
+       // xmm0 =                       // (u_1; u_0)
+       // xmm1 =                       // (v_1; v_0)
+       movdqa  xmm2, xmm1              // (v_1; v_0) again
+       movdqa  xmm3, xmm0              // (u_1; u_0) again
+       movdqa  xmm4, xmm0              // (u_1; u_0) yet again
+       pclmulhqlqdq xmm2, xmm0         // u_1 v_0
+       pclmullqlqdq xmm0, xmm1         // u_1 v_1
+       pclmulhqlqdq xmm3, xmm1         // u_0 v_1
+       pclmulhqhqdq xmm4, xmm1         // u_0 v_0
+
+       // Arrange the pieces to form a double-precision polynomial.
+       pxor    xmm2, xmm3              // (m_1; m_0) = u_1 v_0 + u_0 v_1
+       movdqa  xmm1, xmm2              // (m_1; m_0) again
+       pslldq  xmm2, 8                 // (0; m_1)
+       psrldq  xmm1, 8                 // (m_0; 0)
+       pxor    xmm0, xmm2              // x_1 = u_1 v_1 + m_1
+       pxor    xmm1, xmm4              // x_0 = u_0 v_0 + t^64 m_0
+
+       // Two problems remain.  The first is that this product is shifted
+       // left (from GCM's backwards perspective) by one place, which is
+       // annoying.  Let's take care of that now.  Once this is done, we'll
+       // be properly in GCM's backwards bit-ordering, so xmm1 will hold the
+       // low half of the product and xmm0 the high half.  (The following
+       // diagrams show bit 0 consistently on the right.)
+       //
+       //                               xmm1
+       //    ,-------------.-------------.-------------.-------------.
+       //    | 0  x_0-x_30 |  x_31-x_62  |  x_63-x_94  |  x_95-x_126 |
+       //    `-------------^-------------^-------------^-------------'
+       //
+       //                               xmm0
+       //    ,-------------.-------------.-------------.-------------.
+       //    | x_127-x_158 | x_159-x_190 | x_191-x_222 | x_223-x_254 |
+       //    `-------------^-------------^-------------^-------------'
+       //
+       // We start by shifting each 32-bit lane right (from GCM's point of
+       // view -- physically, left) by one place, which gives us this:
+       //
+       //                           low (xmm3)
+       //    ,-------------.-------------.-------------.-------------.
+       //    | x_0-x_30  0 | x_32-x_62 0 | x_64-x_94 0 | x_96-x_126 0|
+       //    `-------------^-------------^-------------^-------------'
+       //
+       //                           high (xmm2)
+       //    ,-------------.-------------.-------------.-------------.
+       //    |x_128-x_158 0|x_160-x_190 0|x_192-x_222 0|x_224-x_254 0|
+       //    `-------------^-------------^-------------^-------------'
+       //
+       // but we've lost a bunch of bits.  We separately shift each lane
+       // left by 31 places to give us the bits we lost.
+       //
+       //                           low (xmm1)
+       //    ,-------------.-------------.-------------.-------------.
+       //    |    0...0    | 0...0  x_31 | 0...0  x_63 | 0...0  x_95 |
+       //    `-------------^-------------^-------------^-------------'
+       //
+       //                           high (xmm0)
+       //    ,-------------.-------------.-------------.-------------.
+       //    | 0...0 x_127 | 0...0 x_159 | 0...0 x_191 | 0...0 x_223 |
+       //    `-------------^-------------^-------------^-------------'
+       //
+       // Which is close, but we don't get a cigar yet.  To get the missing
+       // bits into position, we shift each of these right by a lane, but,
+       // alas, the x_127 falls off, so, separately, we shift the high
+       // register left by three lanes, so that everything is lined up
+       // properly when we OR them all together:
+       //
+       //                           low (xmm1)
+       //    ,-------------.-------------.-------------.-------------.
+       //    ? 0...0  x_31 | 0...0  x_63 | 0...0  x_95 |    0...0    |
+       //    `-------------^-------------^-------------^-------------'
+       //
+       //                           wrap (xmm4)
+       //    ,-------------.-------------.-------------.-------------.
+       //    |    0...0    |    0...0    |    0...0    | 0...0 x_127 |
+       //    `-------------^-------------^-------------^-------------'
+       //
+       //                           high (xmm0)
+       //    ,-------------.-------------.-------------.-------------.
+       //    | 0...0 x_159 | 0...0 x_191 | 0...0 x_223 |    0...0    |
+       //    `-------------^-------------^-------------^-------------'
+       //
+       // The `low' and `wrap' registers (xmm1, xmm3, xmm4) then collect the
+       // low 128 coefficients, while the `high' registers (xmm0, xmm2)
+       // collect the high 127 registers, leaving a zero bit at the most
+       // significant end as we expect.
+
+       // xmm0 =                       // (x_7, x_6; x_5, x_4)
+       // xmm1 =                       // (x_3, x_2; x_1, x_0)
+       movdqa  xmm3, xmm1              // (x_3, x_2; x_1, x_0) again
+       movdqa  xmm2, xmm0              // (x_7, x_6; x_5, x_4) again
+       psrld   xmm1, 31                // shifted left; just the carries
+       psrld   xmm0, 31
+       pslld   xmm3, 1                 // shifted right, but dropped carries
+       pslld   xmm2, 1
+       movdqa  xmm4, xmm0              // another copy for the carry around
+       pslldq  xmm1, 4                 // move carries over
+       pslldq  xmm0, 4
+       psrldq  xmm4, 12                // the big carry wraps around
+       por     xmm1, xmm3
+       por     xmm0, xmm2              // (y_7, y_6; y_5, y_4)
+       por     xmm1, xmm4              // (y_3, y_2; y_1, y_0)
+
+       // And the other problem is that the result needs to be reduced
+       // modulo p(t) = t^128 + t^7 + t^2 + t + 1.  Let R = t^128 = t^7 +
+       // t^2 + t + 1 in our field.  So far, we've calculated z_0 and z_1
+       // such that z_0 + z_1 R = u v using the identity R = t^128: now we
+       // must collapse the two halves of z together using the other
+       // identity R = t^7 + t^2 + t + 1.
+       //
+       // We do this by working on each 32-bit word of the high half of z
+       // separately, so consider y_i, for some 4 <= i < 8.  Certainly, y_i
+       // t^{32i} = y_i R t^{32(i-4)} = (t^7 + t^2 + t + 1) y_i t^{32(i-4)},
+       // but we can't use that directly without breaking up the 32-bit word
+       // structure.  Instead, we start by considering just y_i t^7
+       // t^{32(i-4)}, which again looks tricky.  Now, split y_i = a_i +
+       // t^25 b_i, with deg a_i < 25; then
+       //
+       //      y_i t^7 t^{32(i-4)} = a_i t^7 t^{32(i-4)} + b_i t^{32(i-3)}
+       //
+       // We can similarly decompose y_i t^2 and y_i t into a pair of 32-bit
+       // contributions to the t^{32(i-4)} and t^{32(i-3)} words, but the
+       // splits are different.  This is lovely, with one small snag: when
+       // we do this to y_7, we end up with a contribution back into the
+       // t^128 coefficient word.  But notice that only the low seven bits
+       // of this word are affected, so there's no knock-on contribution
+       // into the t^32 word.  Therefore, if we handle the high bits of each
+       // word together, and then the low bits, everything will be fine.
+
+       // First, shift the high bits down.
+       movdqa  xmm2, xmm0              // (y_7, y_6; y_5, y_4) again
+       movdqa  xmm3, xmm0              // (y_7, y_6; y_5, y_4) yet again
+       movdqa  xmm4, xmm0              // (y_7, y_6; y_5, y_4) again again
+       pslld   xmm2, 31                // the b_i for t
+       pslld   xmm3, 30                // the b_i for t^2
+       pslld   xmm4, 25                // the b_i for t^7
+       pxor    xmm2, xmm3              // add them all together
+       pxor    xmm2, xmm4
+       movdqa  xmm3, xmm2              // and a copy for later
+       psrldq  xmm2, 4                 // contribution into low half
+       pslldq  xmm3, 12                // and high half
+       pxor    xmm1, xmm2
+       pxor    xmm0, xmm3
+
+       // And then shift the low bits up.
+       movdqa  xmm2, xmm0
+       movdqa  xmm3, xmm0
+       pxor    xmm1, xmm0              // mix in the unit contribution
+       psrld   xmm0, 1
+       psrld   xmm2, 2
+       psrld   xmm3, 7
+       pxor    xmm1, xmm2              // low half, unit, and t^2 contribs
+       pxor    xmm0, xmm3              // t and t^7 contribs
+       pxor    xmm0, xmm1              // mix them together and we're done
+.endm
+
+.macro mul64
+       // Enter with u and v in the low halves of xmm0 and xmm1
+       // respectively; leave with z = u v in xmm0.  Clobbers xmm1--xmm4.
+
+       // The multiplication is thankfully easy.
+       pclmullqlqdq xmm0, xmm1         // u v
+
+       // Shift the product up by one place.  After this, we're in GCM
+       // bizarro-world.
+       movdqa  xmm1, xmm0              // u v again
+       psrld   xmm0, 31                // shifted left; just the carries
+       pslld   xmm1, 1                 // shifted right, but dropped carries
+       pslldq  xmm0, 4                 // move carries over
+       por     xmm1, xmm0              // (y_3, y_2; y_1, y_0)
+
+       // Now we must reduce.  This is essentially the same as the 128-bit
+       // case above, but mostly simpler because everything is smaller.  The
+       // polynomial this time is p(t) = t^64 + t^4 + t^3 + t + 1.
+
+       // First, we must detach the top (`low'!) half of the result.
+       movdqa  xmm0, xmm1              // (y_3, y_2; y_1, y_0) again
+       psrldq  xmm1, 8                 // (y_1, y_0; 0, 0)
+
+       // Next, shift the high bits down.
+       movdqa  xmm2, xmm0              // (y_3, y_2; ?, ?) again
+       movdqa  xmm3, xmm0              // (y_3, y_2; ?, ?) yet again
+       movdqa  xmm4, xmm0              // (y_3, y_2; ?, ?) again again
+       pslld   xmm2, 31                // b_i for t
+       pslld   xmm3, 29                // b_i for t^3
+       pslld   xmm4, 28                // b_i for t^4
+       pxor    xmm2, xmm3              // add them all together
+       pxor    xmm2, xmm4
+       movdqa  xmm3, xmm2              // and a copy for later
+       movq    xmm2, xmm2              // zap high half
+       pslldq  xmm3, 4                 // contribution into high half
+       psrldq  xmm2, 4                 // and low half
+       pxor    xmm0, xmm3
+       pxor    xmm1, xmm2
+
+       // And then shift the low bits up.
+       movdqa  xmm2, xmm0
+       movdqa  xmm3, xmm0
+       pxor    xmm1, xmm0              // mix in the unit contribution
+       psrld   xmm0, 1
+       psrld   xmm2, 3
+       psrld   xmm3, 4
+       pxor    xmm1, xmm2              // low half, unit, and t^3 contribs
+       pxor    xmm0, xmm3              // t and t^4 contribs
+       pxor    xmm0, xmm1              // mix them together and we're done
+.endm
+
+.macro mul96
+       // Enter with u and v in the /high/ three words of xmm0 and xmm1
+       // respectively (and zero in the low word); leave with z = u v in the
+       // high three words of xmm0, and /junk/ in the low word.  Clobbers
+       // xmm1--xmm4.
+
+       // This is an inconvenient size.  There's nothing for it but to do
+       // four multiplications, as if for the 128-bit case.  It's possible
+       // that there's cruft in the top 32 bits of the input registers, so
+       // shift both of them up by four bytes before we start.  This will
+       // mean that the high 64 bits of the result (from GCM's viewpoint)
+       // will be zero.
+       // xmm0 =                       // (0, u_2; u_1, u_0)
+       // xmm1 =                       // (0, v_2; v_1, v_0)
+       movdqa  xmm2, xmm1              // (0, v_2; v_1, v_0) again
+       movdqa  xmm3, xmm0              // (0, u_2; u_1, u_0) again
+       movdqa  xmm4, xmm0              // (0, u_2; u_1, u_0) yet again
+       pclmulhqlqdq xmm2, xmm0         // u_2 (v_1 t^32 + v_0) = e_0
+       pclmullqlqdq xmm0, xmm1         // u_2 v_2 = d = (0; d)
+       pclmulhqlqdq xmm3, xmm1         // v_2 (u_1 t^32 + u_0) = e_1
+       pclmulhqhqdq xmm4, xmm1         // u_0 v_0 + (u_1 v_0 + u_0 v_1) t^32
+                                       //   + u_1 v_1 t^64 = f
+
+       // Extract the high and low halves of the 192-bit result.  We don't
+       // need be too picky about the unused high words of the result
+       // registers.  The answer we want is d t^128 + e t^64 + f, where e =
+       // e_0 + e_1.
+       //
+       // The place values for the two halves are (t^160, t^128; t^96, ?)
+       // and (?, t^64; t^32, 1).
+       psrldq  xmm0, 8                 // (d; 0) = d t^128
+       pxor    xmm2, xmm3              // e = (e_0 + e_1)
+       movdqa  xmm1, xmm4              // f again
+       pxor    xmm0, xmm2              // d t^128 + e t^64
+       psrldq  xmm2, 12                // e[31..0] t^64
+       psrldq  xmm1, 4                 // f[95..0]
+       pslldq  xmm4, 8                 // f[127..96]
+       pxor    xmm1, xmm2              // low 96 bits of result
+       pxor    xmm0, xmm4              // high 96 bits of result
+
+       // Next, shift everything one bit to the left to compensate for GCM's
+       // strange ordering.  This will be easier if we shift up the high
+       // half by a word before we start.  After this we're in GCM bizarro-
+       // world.
+       movdqa  xmm3, xmm1              // low half again
+       pslldq  xmm0, 4                 // shift high half
+       psrld   xmm1, 31                // shift low half down: just carries
+       movdqa  xmm2, xmm0              // copy high half
+       pslld   xmm3, 1                 // shift low half down: drop carries
+       psrld   xmm0, 31                // shift high half up: just carries
+       pslld   xmm2, 1                 // shift high half down: drop carries
+       movdqa  xmm4, xmm0              // copy high carries for carry-around
+       pslldq  xmm0, 4                 // shift carries down
+       pslldq  xmm1, 4
+       psrldq  xmm4, 12                // the big carry wraps around
+       por     xmm1, xmm3
+       por     xmm0, xmm2
+       por     xmm1, xmm4
+
+       // Finally, the reduction.  This is essentially the same as the
+       // 128-bit case, except that the polynomial is p(t) = t^96 + t^10 +
+       // t^9 + t^6 + 1.  The degrees are larger but not enough to cause
+       // trouble for the general approach.
+
+       // First, shift the high bits down.
+       movdqa  xmm2, xmm0              // copies of the high part
+       movdqa  xmm3, xmm0
+       movdqa  xmm4, xmm0
+       pslld   xmm2, 26                // b_i for t^6
+       pslld   xmm3, 23                // b_i for t^9
+       pslld   xmm4, 22                // b_i for t^10
+       pxor    xmm2, xmm3              // add them all together
+       pslldq  xmm1, 4                 // shift low part up to match
+       pxor    xmm2, xmm4
+       movdqa  xmm3, xmm2              // and a copy for later
+       pslldq  xmm2, 8                 // contribution to high half
+       psrldq  xmm3, 4                 // contribution to low half
+       pxor    xmm1, xmm3
+       pxor    xmm0, xmm2
+
+       // And then shift the low bits up.
+       movdqa  xmm2, xmm0              // copies of the high part
+       movdqa  xmm3, xmm0
+       pxor    xmm1, xmm0              // mix in the unit contribution
+       psrld   xmm0, 6
+       psrld   xmm2, 9
+       psrld   xmm3, 10
+       pxor    xmm1, xmm2              // low half, unit, and t^9 contribs
+       pxor    xmm0, xmm3              // t^6 and t^10 contribs
+       pxor    xmm0, xmm1              // mix them together and we're done
+.endm
+
+.macro mul192
+       // Enter with u and v in xmm0/xmm1 and xmm2/xmm3 respectively; leave
+       // with z = u v in xmm0/xmm1 -- the top halves of the high registers
+       // are unimportant.  Clobbers xmm2--xmm7.
+
+       // Start multiplying and accumulating pieces of product.
+       // xmm0 =                       // (u_2; u_1)
+       // xmm1 =                       // (u_0; ?)
+       // xmm2 =                       // (v_2; v_1)
+       // xmm3 =                       // (v_0; ?)
+       movdqa  xmm4, xmm0              // (u_2; u_1) again
+       movdqa  xmm5, xmm0              // (u_2; u_1) yet again
+       movdqa  xmm6, xmm0              // (u_2; u_1) again again
+       movdqa  xmm7, xmm1              // (u_0; ?) again
+       punpcklqdq xmm1, xmm3           // (u_0; v_0)
+       pclmulhqhqdq xmm4, xmm2         // u_1 v_1
+       pclmullqlqdq xmm3, xmm0         // u_2 v_0
+       pclmullqhqdq xmm5, xmm2         // u_2 v_1
+       pclmulhqlqdq xmm6, xmm2         // u_1 v_2
+       pxor    xmm4, xmm3              // u_2 v_0 + u_1 v_1
+       pclmullqlqdq xmm7, xmm2         // u_0 v_2
+       pxor    xmm5, xmm6              // b = u_2 v_1 + u_1 v_2
+       movdqa  xmm6, xmm0              // (u_2; u_1) like a bad penny
+       pxor    xmm4, xmm7              // c = u_0 v_2 + u_1 v_1 + u_2 v_0
+       pclmullqlqdq xmm0, xmm2         // a = u_2 v_2
+       pclmulhqhqdq xmm6, xmm1         // u_1 v_0
+       pclmulhqlqdq xmm2, xmm1         // u_0 v_1
+       pclmullqhqdq xmm1, xmm1         // e = u_0 v_0
+       pxor    xmm2, xmm6              // d = u_1 v_0 + u_0 v_1
+
+       // Next, the piecing together of the product.
+       // xmm0 =                       // (a_1; a_0) = a = u_2 v_2
+       // xmm5 =                       // (b_1; b_0) = b = u_1 v_2 + u_2 v_1
+       // xmm4 =                       // (c_1; c_0) = c = u_0 v_2 +
+                                       //      u_1 v_1 + u_2 v_0
+       // xmm2 =                       // (d_1; d_0) = d = u_0 v_1 + u_1 v_0
+       // xmm1 =                       // (e_1; e_0) = e = u_0 v_0
+       // xmm3, xmm6, xmm7 spare
+       movdqa  xmm3, xmm2              // (d_1; d_0) again
+       movdqa  xmm6, xmm5              // (b_1; b_0) again
+       pslldq  xmm2, 8                 // (0; d_1)
+       psrldq  xmm5, 8                 // (b_0; 0)
+       psrldq  xmm3, 8                 // (d_0; 0)
+       pslldq  xmm6, 8                 // (0; b_1)
+       pxor    xmm5, xmm2              // (b_0; d_1)
+       pxor    xmm0, xmm6              // x_2 = (a_1; a_0 + b_1)
+       pxor    xmm3, xmm1              // x_0 = (e_1 + d_0; e_0)
+       pxor    xmm4, xmm5              // x_1 = (b_0 + c_1; c_0 + d_1)
+
+       // Now, shift it right (from GCM's point of view) by one bit, and try
+       // to leave the result in less random registers.  After this, we'll
+       // be in GCM bizarro-world.
+       // xmm1, xmm2, xmm5, xmm6, xmm7 spare
+       movdqa  xmm5, xmm0              // copy x_2
+       movdqa  xmm1, xmm4              // copy x_1
+       movdqa  xmm2, xmm3              // copy x_0
+       psrld   xmm0, 31                // x_2 carries
+       psrld   xmm4, 31                // x_1 carries
+       psrld   xmm3, 31                // x_0 carries
+       pslld   xmm5, 1                 // x_2 shifted
+       pslld   xmm1, 1                 // x_1 shifted
+       pslld   xmm2, 1                 // x_0 shifted
+       movdqa  xmm6, xmm0              // x_2 carry copy
+       movdqa  xmm7, xmm4              // x_1 carry copy
+       pslldq  xmm0, 4                 // x_2 carry shifted
+       pslldq  xmm4, 4                 // x_1 carry shifted
+       pslldq  xmm3, 4                 // x_0 carry shifted
+       psrldq  xmm6, 12                // x_2 carry out
+       psrldq  xmm7, 12                // x_1 carry out
+       por     xmm0, xmm5              // (y_5; y_4)
+       por     xmm1, xmm4
+       por     xmm2, xmm3
+       por     xmm1, xmm6              // (y_3; y_2)
+       por     xmm2, xmm7              // (y_1; y_0)
+
+       // Next, the reduction.  Our polynomial this time is p(x) = t^192 +
+       // t^7 + t^2 + t + 1.  Yes, the magic numbers are the same as the
+       // 128-bit case.  I don't know why.
+
+       // First, shift the high bits down.
+       // xmm0 =                       // (y_5; y_4)
+       // xmm1 =                       // (y_3; y_2)
+       // xmm2 =                       // (y_1; y_0)
+       // xmm3--xmm7 spare
+       movdqa  xmm3, xmm0              // (y_5; y_4) copy
+       movdqa  xmm4, xmm0              // (y_5; y_4) copy
+       movdqa  xmm5, xmm0              // (y_5; y_4) copy
+       pslld   xmm3, 31                // (y_5; y_4) b_i for t
+       pslld   xmm4, 30                // (y_5; y_4) b_i for t^2
+       pslld   xmm5, 25                // (y_5; y_4) b_i for t^7
+        movq   xmm6, xmm1              // (y_3; 0) copy
+       pxor    xmm3, xmm4
+        movq   xmm7, xmm1              // (y_3; 0) copy
+       pxor    xmm3, xmm5
+        movq   xmm5, xmm1              // (y_3; 0) copy
+       movdqa  xmm4, xmm3              // (y_5; y_4) b_i combined
+        pslld  xmm6, 31                // (y_3; 0) b_i for t
+        pslld  xmm7, 30                // (y_3; 0) b_i for t^2
+        pslld  xmm5, 25                // (y_3; 0) b_i for t^7
+       psrldq  xmm3, 12                // (y_5; y_4) low contrib
+       pslldq  xmm4, 4                 // (y_5; y_4) high contrib
+        pxor   xmm6, xmm7
+       pxor    xmm2, xmm3
+        pxor   xmm6, xmm5
+       pxor    xmm1, xmm4
+        pslldq xmm6, 4
+        pxor   xmm2, xmm6
+
+       // And finally shift the low bits up.  Unfortunately, we also have to
+       // split the low bits out.
+       // xmm0 =                       // (y'_5; y'_4)
+       // xmm1 =                       // (y'_3; y'_2)
+       // xmm2 =                       // (y'_1; y'_0)
+        movdqa xmm5, xmm1              // copies of (y'_3; y'_2)
+        movdqa xmm6, xmm1
+        movdqa xmm7, xmm1
+         psrldq xmm1, 8                // bring down (y'_2; ?)
+       movdqa  xmm3, xmm0              // copies of (y'_5; y'_4)
+       movdqa  xmm4, xmm0
+         punpcklqdq  xmm1, xmm2        // (y'_2; y'_1)
+         psrldq xmm2, 8                // (y'_0; ?)
+        pxor   xmm2, xmm5              // low half and unit contrib
+       pxor    xmm1, xmm0
+        psrld  xmm5, 1
+       psrld   xmm0, 1
+        psrld  xmm6, 2
+       psrld   xmm3, 2
+        psrld  xmm7, 7
+       psrld   xmm4, 7
+        pxor   xmm2, xmm6              // low half, unit, t^2 contribs
+       pxor    xmm1, xmm3
+        pxor   xmm5, xmm7              // t and t^7 contribs
+       pxor    xmm0, xmm4
+        pxor   xmm5, xmm2              // mix everything together
+       pxor    xmm0, xmm1
+        movq   xmm1, xmm5              // shunt (z_0; ?) into proper place
+.endm
+
+.macro mul256
+       // Enter with u and v in xmm0/xmm1 and xmm2/xmm3 respectively; leave
+       // with z = u v in xmm0/xmm1.  Clobbers xmm2--xmm7.  On 32-bit x86,
+       // requires 16 bytes aligned space at SP; on amd64, also clobbers
+       // xmm8.
+
+       // Now it's starting to look worthwhile to do Karatsuba.  Suppose
+       // u = u_0 + u_1 B and v = v_0 + v_1 B.  Then
+       //
+       //      u v = (u_0 v_0) + (u_0 v_1 + u_1 v_0) B + (u_1 v_1) B^2
+       //
+       // Name these coefficients of B^i be a, b, and c, respectively, and
+       // let r = u_0 + u_1 and s = v_0 + v_1.  Then observe that
+       //
+       //      q = r s = (u_0 + u_1) (v_0 + v_1)
+       //        = (u_0 v_0) + (u1 v_1) + (u_0 v_1 + u_1 v_0)
+       //        = a + d + c
+       //
+       // The first two terms we've already calculated; the last is the
+       // remaining one we want.  We'll set B = t^128.  We know how to do
+       // 128-bit multiplications already, and Karatsuba is too annoying
+       // there, so there'll be 12 multiplications altogether, rather than
+       // the 16 we'd have if we did this the naïve way.
+       //
+       // On x86, there aren't quite enough registers, so spill one for a
+       // bit.  On AMD64, we can keep on going, so it's all good.
+
+       // xmm0 =                       // u_1 = (u_11; u_10)
+       // xmm1 =                       // u_0 = (u_01; u_00)
+       // xmm2 =                       // v_1 = (v_11; v_10)
+       // xmm3 =                       // v_0 = (v_01; v_00)
+       movdqa  xmm4, xmm0              // u_1 again
+#if CPUFAM_X86
+       movdqa  [esp + 0], xmm3
+#elif CPUFAM_AMD64
+       movdqa  xmm8, xmm3
+#  define V0 xmm8
+#endif
+       pxor    xmm4, xmm1              // u_* = (u_01 + u_11; u_00 + u_10)
+       pxor    xmm3, xmm2              // v_* = (v_01 + v_11; v_00 + v_10)
+
+       // Start by building the cross product, q = u_* v_*.
+       movdqa  xmm7, xmm4              // more copies of u_*
+       movdqa  xmm5, xmm4
+       movdqa  xmm6, xmm4
+       pclmullqhqdq xmm4, xmm3         // u_*1 v_*0
+       pclmulhqlqdq xmm7, xmm3         // u_*0 v_*1
+       pclmullqlqdq xmm5, xmm3         // u_*1 v_*1
+       pclmulhqhqdq xmm6, xmm3         // u_*0 v_*0
+       pxor    xmm4, xmm7              // u_*1 v_*0 + u_*0 v_*1
+       movdqa  xmm7, xmm4
+       pslldq  xmm4, 8
+       psrldq  xmm7, 8
+       pxor    xmm5, xmm4              // q_1
+       pxor    xmm6, xmm7              // q_0
+
+       // Next, work on the high half, a = u_1 v_1.
+       movdqa  xmm3, xmm0              // more copies of u_1
+       movdqa  xmm4, xmm0
+       movdqa  xmm7, xmm0
+       pclmullqhqdq xmm0, xmm2         // u_11 v_10
+       pclmulhqlqdq xmm3, xmm2         // u_10 v_11
+       pclmullqlqdq xmm4, xmm2         // u_11 v_11
+       pclmulhqhqdq xmm7, xmm2         // u_10 v_10
+#if CPUFAM_X86
+       movdqa  xmm2, [esp + 0]
+#  define V0 xmm2
+#endif
+       pxor    xmm0, xmm3              // u_10 v_11 + u_11 v_10
+       movdqa  xmm3, xmm0
+       pslldq  xmm0, 8
+       psrldq  xmm3, 8
+       pxor    xmm4, xmm0              // x_1 = a_1
+       pxor    xmm7, xmm3              // a_0
+
+       // Mix that into the product now forming in xmm4--xmm7.
+       pxor    xmm5, xmm4              // a_1 + q_1
+       pxor    xmm6, xmm7              // a_0 + q_0
+       pxor    xmm5, xmm7              // a_0 + (a_1 + q_1)
+
+       // Finally, the low half, c = u_0 v_0.
+       movdqa  xmm0, xmm1              // more copies of u_0
+       movdqa  xmm3, xmm1
+       movdqa  xmm7, xmm1
+       pclmullqhqdq xmm1, V0           // u_01 v_00
+       pclmulhqlqdq xmm0, V0           // u_00 v_01
+       pclmullqlqdq xmm3, V0           // u_01 v_01
+       pclmulhqhqdq xmm7, V0           // u_00 v_00
+       pxor    xmm0, xmm1              // u_10 v_11 + u_11 v_10
+       movdqa  xmm1, xmm0
+       pslldq  xmm0, 8
+       psrldq  xmm1, 8
+       pxor    xmm3, xmm0              // c_1
+       pxor    xmm7, xmm1              // x_0 = c_0
+
+       // And mix that in to complete the product.
+       pxor    xmm6, xmm3              // (a_0 + q_0) + c_1
+       pxor    xmm5, xmm3       // x_2 = a_0 + (a_1 + c_1 + q_1) = a_0 + b_1
+       pxor    xmm6, xmm7       // x_1 = (a_0 + c_0 + q_0) + c_1 = b_0 + c_1
+
+#undef V0
+
+       // Now we need to shift that whole lot one bit to the left.  This
+       // will also give us an opportunity to put the product back in
+       // xmm0--xmm3.  This is a slightly merry dance because it's nearly
+       // pipelined but we don't have enough registers.
+       //
+       // After this, we'll be in GCM bizarro-world.
+       movdqa  xmm0, xmm4              // x_3 again
+       psrld   xmm4, 31                // x_3 carries
+       pslld   xmm0, 1                 // x_3 shifted left
+       movdqa  xmm3, xmm4              // x_3 copy carries
+        movdqa xmm1, xmm5              // x_2 again
+       pslldq  xmm4, 4                 // x_3 carries shifted up
+        psrld  xmm5, 31                // x_2 carries
+       psrldq  xmm3, 12                // x_3 big carry out
+        pslld  xmm1, 1                 // x_2 shifted left
+       por     xmm0, xmm4              // x_3 mixed together
+        movdqa xmm4, xmm5              // x_2 copy carries
+         movdqa xmm2, xmm6             // x_1 again
+        pslldq xmm5, 4                 // x_2 carries shifted up
+         psrld xmm6, 31                // x_1 carries
+        psrldq xmm4, 12                // x_2 big carry out
+         pslld xmm2, 1                 // x_1 shifted
+        por    xmm1, xmm5              // x_2 mixed together
+         movdqa xmm5, xmm6             // x_1 copy carries
+        por    xmm1, xmm3              // x_2 with carry from x_3
+          movdqa xmm3, xmm7            // x_0 again
+         pslldq xmm6, 4                // x_1 carries shifted up
+          psrld xmm7, 31               // x_2 carries
+         psrldq xmm5, 12               // x_1 big carry out
+          pslld xmm3, 1                // x_0 shifted
+         por   xmm2, xmm6              // x_1 mixed together
+          pslldq xmm7, 4               // x_0 carries shifted up
+         por   xmm2, xmm4              // x_1 with carry from x_2
+          por  xmm3, xmm7              // x_0 mixed together
+          por  xmm3, xmm5              // x_0 with carry from x_1
+
+       // Now we must reduce.  This is essentially the same as the 128-bit
+       // case above, but more complicated because everything is bigger.
+       // The polynomial this time is p(t) = t^256 + t^10 + t^5 + t^2 + 1.
+
+       // First, shift the high bits down.
+       movdqa  xmm4, xmm0              // y_3 again
+       movdqa  xmm5, xmm0              // y_3 yet again
+       movdqa  xmm6, xmm0              // y_3 again again
+       pslld   xmm4, 30                // y_3: b_i for t^2
+       pslld   xmm5, 27                // y_3: b_i for t^5
+       pslld   xmm6, 22                // y_3: b_i for t^10
+        movdqa xmm7, xmm1              // y_2 again
+       pxor    xmm4, xmm5
+        movdqa xmm5, xmm1              // y_2 again
+       pxor    xmm4, xmm6
+        movdqa xmm6, xmm1              // y_2 again
+        pslld  xmm7, 30                // y_2: b_i for t^2
+        pslld  xmm5, 27                // y_2: b_i for t^5
+        pslld  xmm6, 22                // y_2: b_i for t^10
+        pxor   xmm7, xmm5
+       movdqa  xmm5, xmm4
+        pxor   xmm7, xmm6
+       psrldq  xmm4, 4
+        movdqa xmm6, xmm7
+       pslldq  xmm5, 12
+        psrldq xmm7, 4
+       pxor    xmm2, xmm4
+        pslldq xmm6, 12
+        pxor   xmm3, xmm7
+       pxor    xmm1, xmm5
+        pxor   xmm2, xmm6
+
+       // And then shift the low bits up.
+       movdqa  xmm4, xmm0              // y_3 again
+        movdqa xmm5, xmm1              // y_2 again
+       movdqa  xmm6, xmm0              // y_3 yet again
+        movdqa xmm7, xmm1              // y_2 yet again
+       pxor    xmm2, xmm0              // y_1 and unit contrib from y_3
+        pxor   xmm3, xmm1              // y_0 and unit contrib from y_2
+       psrld   xmm0, 2
+        psrld  xmm1, 2
+       psrld   xmm4, 5
+        psrld  xmm5, 5
+       psrld   xmm6, 10
+        psrld  xmm7, 10
+       pxor    xmm0, xmm2              // y_1, with y_3 units and t^2
+        pxor   xmm1, xmm3              // y_0, with y_2 units and t^2
+       pxor    xmm4, xmm6              // y_3 t^5 and t^10 contribs
+        pxor   xmm5, xmm7              // y_2 t^5 and t^10 contribs
+       pxor    xmm0, xmm4              // high half of reduced result
+       pxor    xmm1, xmm5              // low half; all done
+.endm
+
+///--------------------------------------------------------------------------
+/// Main code.
+
+// There are a number of representations of field elements in this code and
+// it can be confusing.
+//
+//   * The `external format' consists of a sequence of contiguous bytes in
+//     memory called a `block'.  The GCM spec explains how to interpret this
+//     block as an element of a finite field.  As discussed extensively, this
+//     representation is very annoying for a number of reasons.  On the other
+//     hand, this code never actually deals with it directly.
+//
+//   * The `register format' consists of one or more XMM registers, depending
+//     on the block size.  The bytes in these registers are in reverse order
+//     -- so the least-significant byte of the lowest-numbered register holds
+//     the /last/ byte in the block.  If the block size is not a multiple of
+//     16 bytes, then there must be padding.  96-bit blocks are weird: the
+//     padding is inserted at the /least/ significant end, so the register
+//     holds (0, x_0; x_1, x_2); otherwise, the padding goes at the most
+//     significant end.
+//
+//   * The `words' format consists of a sequence of bytes, as in the
+//     `external format', but, according to the blockcipher in use, the bytes
+//     within each 32-bit word may be reversed (`big-endian') or not
+//     (`little-endian').  Accordingly, there are separate entry points for
+//     each variant, identified with `b' or `l'.
+
+#define SSEFUNC(f)                                                     \
+       FUNC(f##_avx); vzeroupper; endprologue; ENDFUNC;                \
+       FUNC(f)
+
+SSEFUNC(gcm_mulk_128b_x86ish_pclmul)
+       // On entry, A points to a 128-bit field element in big-endian words
+       // format; K points to a field-element in register format.  On exit,
+       // A is updated with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+#endif
+  endprologue
+       movdqu  xmm0, [A]
+       movdqu  xmm1, [K]
+       pshufd  xmm0, xmm0, SHUF(3, 2, 1, 0)
+       mul128
+       pshufd  xmm0, xmm0, SHUF(3, 2, 1, 0)
+       movdqu  [A], xmm0
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_128l_x86ish_pclmul)
+       // On entry, A points to a 128-bit field element in little-endian
+       // words format; K points to a field-element in register format.  On
+       // exit, A is updated with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+       ldgot   ecx
+#endif
+  endprologue
+       movdqa  xmm7, [INTADDR(swaptab_128l, ecx)]
+       movdqu  xmm0, [A]
+       movdqu  xmm1, [K]
+       pshufb  xmm0, xmm7
+       mul128
+       pshufb  xmm0, xmm7
+       movdqu  [A], xmm0
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_64b_x86ish_pclmul)
+       // On entry, A points to a 64-bit field element in big-endian words
+       // format; K points to a field-element in register format.  On exit,
+       // A is updated with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+#endif
+  endprologue
+       movq    xmm0, [A]
+       movq    xmm1, [K]
+       pshufd  xmm0, xmm0, SHUF(1, 0, 3, 3)
+       mul64
+       pshufd  xmm0, xmm0, SHUF(1, 0, 3, 3)
+       movq    [A], xmm0
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_64l_x86ish_pclmul)
+       // On entry, A points to a 64-bit field element in little-endian
+       // words format; K points to a field-element in register format.  On
+       // exit, A is updated with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+       ldgot   ecx
+#endif
+  endprologue
+       movdqa  xmm7, [INTADDR(swaptab_64l, ecx)]
+       movq    xmm0, [A]
+       movq    xmm1, [K]
+       pshufb  xmm0, xmm7
+       mul64
+       pshufb  xmm0, xmm7
+       movq    [A], xmm0
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_96b_x86ish_pclmul)
+       // On entry, A points to a 96-bit field element in big-endian words
+       // format; K points to a field-element in register format (i.e., 16
+       // bytes, with the first four bytes zero).  On exit, A is updated
+       // with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+#endif
+  endprologue
+       movq    xmm0, [A + 0]
+       movd    xmm2, [A + 8]
+       movdqu  xmm1, [K]
+       punpcklqdq xmm0, xmm2
+       pshufd  xmm0, xmm0, SHUF(3, 2, 1, 0)
+       mul96
+       pshufd  xmm1, xmm0, SHUF(3, 2, 1, 0)
+       psrldq  xmm0, 4
+       movq    [A + 0], xmm1
+       movd    [A + 8], xmm0
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_96l_x86ish_pclmul)
+       // On entry, A points to a 96-bit field element in little-endian
+       // words format; K points to a field-element in register format
+       // (i.e., 16 bytes, with the first four bytes zero).  On exit, A is
+       // updated with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+       ldgot   ecx
+#endif
+  endprologue
+       movdqa  xmm7, [INTADDR(swaptab_128l, ecx)]
+       movq    xmm0, [A + 0]
+       movd    xmm2, [A + 8]
+       movdqu  xmm1, [K]
+       punpcklqdq xmm0, xmm2
+       pshufb  xmm0, xmm7
+       mul96
+       pshufb  xmm0, xmm7
+       movq    [A + 0], xmm0
+       psrldq  xmm0, 8
+       movd    [A + 8], xmm0
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_192b_x86ish_pclmul)
+       // On entry, A points to a 192-bit field element in big-endian words
+       // format; K points to a field-element in register format.  On exit,
+       // A is updated with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+       stalloc 2*16 + 8
+       savexmm xmm6, 0
+       savexmm xmm7, 16
+#endif
+  endprologue
+       movdqu  xmm0, [A + 8]
+       movq    xmm1, [A + 0]
+       movdqu  xmm2, [K + 0]
+       movq    xmm3, [K + 16]
+       pshufd  xmm0, xmm0, SHUF(3, 2, 1, 0)
+       pshufd  xmm1, xmm1, SHUF(1, 0, 3, 3)
+       mul192
+       pshufd  xmm0, xmm0, SHUF(3, 2, 1, 0)
+       pshufd  xmm1, xmm1, SHUF(1, 0, 3, 3)
+       movdqu  [A + 8], xmm0
+       movq    [A + 0], xmm1
+#if CPUFAM_AMD64 && ABI_WIN
+       rstrxmm xmm6, 0
+       rstrxmm xmm7, 16
+       stfree  2*16 + 8
+#endif
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_192l_x86ish_pclmul)
+       // On entry, A points to a 192-bit field element in little-endian
+       // words format; K points to a field-element in register format.  On
+       // exit, A is updated with the product A K.
+
+#if CPUFAM_X86
+       mov     A, [esp + 4]
+       mov     K, [esp + 8]
+       ldgot   ecx
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+       stalloc 2*16 + 8
+       savexmm xmm6, 0
+       savexmm xmm7, 16
+#endif
+  endprologue
+       movdqu  xmm0, [A + 8]
+       movq    xmm1, [A + 0]
+       movdqu  xmm2, [K + 0]
+       movq    xmm3, [K + 16]
+       pshufb  xmm0, [INTADDR(swaptab_128l, ecx)]
+       pshufb  xmm1, [INTADDR(swaptab_64l, ecx)]
+       mul192
+       pshufb  xmm0, [INTADDR(swaptab_128l, ecx)]
+       pshufb  xmm1, [INTADDR(swaptab_64l, ecx)]
+       movdqu  [A + 8], xmm0
+       movq    [A + 0], xmm1
+#if CPUFAM_AMD64 && ABI_WIN
+       rstrxmm xmm6, 0
+       rstrxmm xmm7, 16
+       stfree  2*16 + 8
+#endif
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_256b_x86ish_pclmul)
+       // On entry, A points to a 256-bit field element in big-endian words
+       // format; K points to a field-element in register format.  On exit,
+       // A is updated with the product A K.
+
+#if CPUFAM_X86
+       pushreg ebp
+       setfp
+       mov     A, [esp + 8]
+       mov     K, [esp + 12]
+       and     esp, ~15
+       sub     esp, 16
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+       stalloc 3*16 + 8
+       savexmm xmm6, 0
+       savexmm xmm7, 16
+       savexmm xmm8, 32
+#endif
+  endprologue
+       movdqu  xmm0, [A + 16]
+       movdqu  xmm1, [A + 0]
+       movdqu  xmm2, [K + 0]
+       movdqu  xmm3, [K + 16]
+       pshufd  xmm0, xmm0, SHUF(3, 2, 1, 0)
+       pshufd  xmm1, xmm1, SHUF(3, 2, 1, 0)
+       mul256
+       pshufd  xmm0, xmm0, SHUF(3, 2, 1, 0)
+       pshufd  xmm1, xmm1, SHUF(3, 2, 1, 0)
+       movdqu  [A + 16], xmm0
+       movdqu  [A + 0], xmm1
+#if CPUFAM_X86
+       dropfp
+       popreg  ebp
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+       rstrxmm xmm6, 0
+       rstrxmm xmm7, 16
+       rstrxmm xmm8, 32
+       stfree  3*16 + 8
+#endif
+       ret
+ENDFUNC
+
+SSEFUNC(gcm_mulk_256l_x86ish_pclmul)
+       // On entry, A points to a 256-bit field element in little-endian
+       // words format; K points to a field-element in register format.  On
+       // exit, A is updated with the product A K.
+
+#if CPUFAM_X86
+       pushreg ebp
+       setfp
+       mov     A, [esp + 8]
+       mov     K, [esp + 12]
+       and     esp, ~15
+       ldgot   ecx
+       sub     esp, 16
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+       stalloc 3*16 + 8
+       savexmm xmm6, 0
+       savexmm xmm7, 16
+       savexmm xmm8, 32
+#endif
+  endprologue
+       movdqa  xmm7, [INTADDR(swaptab_128l, ecx)]
+       movdqu  xmm0, [A + 16]
+       movdqu  xmm1, [A + 0]
+       movdqu  xmm2, [K + 0]
+       movdqu  xmm3, [K + 16]
+       pshufb  xmm0, xmm7
+       pshufb  xmm1, xmm7
+       mul256
+       movdqa  xmm7, [INTADDR(swaptab_128l, ecx)]
+       pshufb  xmm0, xmm7
+       pshufb  xmm1, xmm7
+       movdqu  [A + 16], xmm0
+       movdqu  [A + 0], xmm1
+#if CPUFAM_X86
+       dropfp
+       popreg  ebp
+#endif
+#if CPUFAM_AMD64 && ABI_WIN
+       rstrxmm xmm6, 0
+       rstrxmm xmm7, 16
+       rstrxmm xmm8, 32
+       stfree  3*16 + 8
+#endif
+       ret
+ENDFUNC
+
+       RODATA
+
+       .balign 16
+swaptab_128l:
+       // Table for byte-swapping little-endian words-format blocks larger
+       // than 64 bits.
+       .byte    15,  14,  13,  12,   11,  10,   9,   8
+       .byte     7,   6,   5,   4,    3,   2,   1,   0
+
+       .balign 16
+swaptab_64l:
+       // Table for byte-swapping 64-bit little-endian words-format blocks.
+       .byte     7,   6,   5,   4,    3,   2,   1,   0
+       .byte   255, 255, 255, 255,  255, 255, 255, 255
+
+///----- That's all, folks --------------------------------------------------
diff --git a/symm/gcm.c b/symm/gcm.c
new file mode 100644 (file)
index 0000000..73b2851
--- /dev/null
@@ -0,0 +1,882 @@
+/* -*-c-*-
+ *
+ * The GCM authenticated encryption mode
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <mLib/bits.h>
+
+#include "dispatch.h"
+#include "gcm.h"
+#include "gcm-def.h"
+
+/*----- Overall strategy --------------------------------------------------*
+ *
+ * GCM is pretty awful to implement in software.  (This presentation is going
+ * to be somewhat different to that in the specification, but I think it
+ * makes more sense like this.)
+ *
+ * We're given a %$w$%-bit blockcipher %$E$% with a key %$K$%.
+ *
+ * The main part is arithmetic in the finite field %$k = \gf{2^w}$%, which we
+ * represent as the quotient ring %$\gf{2}[t]/(p_w(t))$% for some irreducible
+ * degree-%$w$% polynomial %$p(t)$%, whose precise value isn't very important
+ * right now.  We choose a secret point %$x = E_K(0^w)$%.
+ *
+ * We choose a length size %$z$% as follows: if %$w < 96%$ then %$z = w$%;
+ * otherwise %$z = w/2$%.  Format a message pair as follows:
+ *
+ *     %$F(a, b) = P_w(a) \cat P_w(b) \cat [\ell(a)]_z \cat [\ell(b)]_z$%
+ *
+ * where %$P_w(x) = x \cat 0^n$% where $%0 \le n < w$% such that
+ * %$\ell(x) + n \equiv 0 \pmod{w}$%.
+ *
+ * Hash a (block-aligned) message %$u$% as follows.  First, split %$u$% into
+ * %$w$%-bit blocks %$u_0$%, %$u_1$%, %%\ldots%%, %$u_{n-1}$%.  Interpret
+ * these as elements of %$k$%.  Then
+ *
+ *     %$G_x(u) = u_0 t^n + u_1 t^{n-1} + \cdots + u_{n-1} t$%
+ *
+ * converted back to a %$w$%-bit string.
+ *
+ * We're ready to go now.  Suppose we're to encrypt a message %$M$% with
+ * header %$H$% and nonce %$N$%.  If %$\ell(N) + 32 = w$% then let
+ * %$N' = N$% and let %$i_0 = 1$%; otherwise, let %$U = G_t(F(\epsilon, N))$%
+ * and split this into %$N' = U[0 \bitsto w - 32]$% and
+ * %$[i_0]_{32} = U[w - 32 \bitsto w]$%.
+ *
+ * Let %$n = \lceil \ell(M)/w \rceil$%.  Compute
+ *
+ *     %$y_j = E_K(N' \cat [i_0 + j]_{32})$%
+ *
+ * for %$0 \le j \le n$%.  Let
+ *
+ *     %$s = (y_1 \cat y_2 \cat \cdots \cat y_n)[0 \bitsto \ell(M)$%
+ *
+ * Let %$C = M \xor s$% and let %$T = G_x(F(H, C)) \xor y_0$%.  These are the
+ * ciphertext and tag respectively.
+ *
+ * So why is this awful?
+ *
+ * For one thing, the bits are in a completely terrible order.  The bytes are
+ * arranged in little-endian order, so the unit coefficient is in the first
+ * byte, and the degree-127 coefficient is in the last byte.  But within each
+ * byte, the lowest-degree coefficient is in the most significant bit.  It's
+ * therefore better to think of GCM as using a big-endian byte-ordering
+ * convention, but with the bits backwards.
+ *
+ * But messing about with byte ordering is expensive, so let's not do that in
+ * the inner loop.  But multiplication in %$k$% is not easy either.  Some
+ * kind of precomputed table would be nice, but that will leak secrets
+ * through the cache.
+ *
+ * I choose a particularly simple table: given %$x$%, let %$X[i'] = x t^i$%.
+ * Then $%$x y = \sum_{0\le i<w} y_i X[i']$% which is just a bunch of
+ * bitmasking.  But the natural order for examining bits of %$y$% is not
+ * necessarily the obvious one.  We'll have already loaded %$y$% into
+ * internal form, as 32-bit words.  The good order to process these is left
+ * to right, from high to low bits.  But now the order of degrees depends on
+ * the endianness of our conversion of bytes to words.  Oh, well.
+ *
+ * If we've adopted a big-endian convention, then we'll see the degrees in
+ * order, 0, 1, ..., all the way up to %$w - 1$% and everything is fine.  If
+ * we've adopted a little-endian convention, though, we'll see an ordering
+ * like this:
+ *
+ *     24, 25, ..., 31, 16, 17, ..., 23,  8,  9, ..., 15,  0,  1, ..., 7,
+ *     56, 57, ..., 63, 48, 49, ..., 55, 40, 41, ..., 47, 32, 33, ..., 39,
+ *     etc.
+ *
+ * which is the ordinary order with 0x18 = 24 XORed into the index.  That is,
+ * %$i' = i$% if we've adopted a big-endian convention, and
+ * %$i' = i \xor 24$% if we've adopted a little-endian convention.
+ */
+
+/*----- Low-level utilities -----------------------------------------------*/
+
+/* --- @mult@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *z@ = where to write the result
+ *             @const uint32 *x@ = input field element
+ *
+ * Returns:    ---
+ *
+ * Use:                Multiply the input field element by %$t$%, and write the
+ *             product to @z@.  It's safe for @x@ and @z@ to be equal, but
+ *             they should not otherwise overlap.  Both input and output are
+ *             in big-endian form, i.e., with the lowest-degree coefficients
+ *             in the most significant bits.
+ */
+
+static void mult(const gcm_params *p, uint32 *z, const uint32 *x)
+{
+  uint32 m, c, t;
+  unsigned i;
+
+  t = x[p->n - 1]; m = -(t&1u); c = m&p->poly;
+  for (i = 0; i < p->n; i++) { t = x[i]; z[i] = (t >> 1) ^ c; c = t << 31; }
+}
+
+/* --- @mul@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *z@ = where to write the result
+ *             @const uint32 *x, *y@ = input field elements
+ *
+ * Returns:    ---
+ *
+ * Use:                Multiply the input field elements together, and write the
+ *             product to @z@.  It's safe for the operands to overlap.  Both
+ *             inputs and the output are in big-endian form, i.e., with the
+ *             lowest-degree coefficients in the most significant bits.
+ */
+
+static void mul(const gcm_params *p, uint32 *z,
+               const uint32 *x, const uint32 *y)
+{
+  uint32 m, t, u[GCM_NMAX], v[GCM_NMAX];
+  unsigned i, j, k;
+
+  /* We can't do this in-place at all, so use temporary space.  Make a copy
+   * of @x@ in @u@, where we can clobber it, and build the product in @v@.
+   */
+  for (i = 0; i < p->n; i++) { u[i] = x[i]; v[i] = 0; }
+
+  /* Repeatedly multiply @x@ (in @u@) by %$t$%, and add together those
+   * %$x t^i$% selected by the bits of @y@.  This is basically what you get
+   * by streaming the result of @gcm_mktable@ into @gcm_mulk_...@.
+   */
+  for (i = 0; i < p->n; i++) {
+    t = y[i];
+    for (j = 0; j < 32; j++) {
+      m = -((t >> 31)&1u);
+      for (k = 0; k < p->n; k++) v[k] ^= u[k]&m;
+      mult(p, u, u); t <<= 1;
+    }
+  }
+
+  /* Write out the result now that it's ready. */
+  for (i = 0; i < p->n; i++) z[i] = v[i];
+}
+
+/*----- Table-based multiplication ----------------------------------------*/
+
+/* --- @gcm_mktable@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *ktab@ = where to write the table; there must be
+ *                     space for %$32 n$% $%n$%-word entries, i.e.,
+ *                     %$32 n^2$% 32-bit words in total, where %$n$% is
+ *                     @p->n@, the block size in words
+ *             @const uint32 *k@ = input field element
+ *
+ * Returns:    ---
+ *
+ * Use:                Construct a table for use by @gcm_mulk_...@ below, to
+ *             multiply (vaguely) efficiently by @k@.
+ */
+
+static void simple_mktable(const gcm_params *p,
+                          uint32 *ktab, const uint32 *k)
+{
+  unsigned m = (p->f&GCMF_SWAP ? 0x18 : 0);
+  unsigned i, j, o = m*p->n;
+
+  /* As described above, the table stores entries %$K[i \xor m] = k t^i$%,
+   * where %$m = 0$% (big-endian cipher) or %$m = 24$% (little-endian).
+   * The first job is to store %$K[m] = k$%.
+   *
+   * We initially build the table with the entries in big-endian order, and
+   * then swap them if necessary.  This makes the arithmetic functions more
+   * amenable for use by @gcm_concat@ below.
+   */
+  if (!(p->f&GCMF_SWAP)) for (i = 0; i < p->n; i++) ktab[o + i] = k[i];
+  else for (i = 0; i < p->n; i++) ktab[o + i] = ENDSWAP32(k[i]);
+
+  /* Fill in the rest of the table by repeatedly multiplying the previous
+   * entry by %$t$%.
+   */
+  for (i = 1; i < 32*p->n; i++)
+    { j = (i ^ m)*p->n; mult(p, ktab + j, ktab + o); o = j; }
+
+  /* Finally, if the cipher uses a little-endian convention, then swap all of
+   * the individual words.
+   */
+  if (p->f&GCMF_SWAP)
+    for (i = 0; i < 32*p->n*p->n; i++) ktab[i] = ENDSWAP32(ktab[i]);
+}
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+static void pclmul_mktable(const gcm_params *p,
+                          uint32 *ktab, const uint32 *k)
+{
+  unsigned n = p->n;
+  unsigned nz;
+  uint32 *t;
+
+  /* We just need to store the value in a way which is convenient for the
+   * assembler code to read back.  That involves reordering the words, and,
+   * in the case of 96-bit blocks, padding with zeroes to fill out a 128-bit
+   * chunk.
+   */
+
+  if (n == 3) nz = 1;
+  else nz = 0;
+  t = ktab + n + nz;
+
+  if (p->f&GCMF_SWAP) while (n--) { *--t = ENDSWAP32(*k); k++; }
+  else while (n--) *--t = *k++;
+  while (nz--) *--t = 0;
+}
+#endif
+
+#if CPUFAM_ARMEL
+static void arm_crypto_mktable(const gcm_params *p,
+                              uint32 *ktab, const uint32 *k)
+{
+  unsigned n = p->n;
+  uint32 *t;
+
+  /* We just need to store the value in a way which is convenient for the
+   * assembler code to read back.  That involves swapping the bytes in each
+   * 64-bit lane.
+   */
+
+  t = ktab;
+  if (p->f&GCMF_SWAP) {
+    while (n >= 2) {
+      t[1] = ENDSWAP32(k[0]); t[0] = ENDSWAP32(k[1]);
+      t += 2; k += 2; n -= 2;
+    }
+    if (n) { t[1] = ENDSWAP32(k[0]); t[0] = 0; }
+  } else {
+    while (n >= 2) {
+      t[1] = k[0]; t[0] = k[1];
+      t += 2; k += 2; n -= 2;
+    }
+    if (n) { t[1] = k[0]; t[0] = 0; }
+  }
+}
+#endif
+
+#if CPUFAM_ARM64
+static uint32 rbit32(uint32 x)
+{
+  uint32 z, t;
+
+#if GCC_VERSION_P(4, 3)
+  /* Two tricks here.  Firstly, two separate steps, rather than a single
+   * block of assembler, to allow finer-grained instruction scheduling.
+   * Secondly, use `ENDSWAP32' so that the compiler can cancel it if the
+   * caller actually wants the bytes reordered.
+   */
+  __asm__("rbit %w0, %w1" : "=r"(t) : "r"(x));
+  z = ENDSWAP32(t);
+#else
+  /* A generic but slightly clever implementation. */
+#  define SWIZZLE(x, m, s) ((((x)&(m)) << (s)) | (((x)&~(m)) >> (s)))
+                                       /* 76543210 */
+  t = SWIZZLE(x, 0x0f0f0f0f, 4);       /* 32107654 -- swap nibbles */
+  t = SWIZZLE(t, 0x33333333, 2);       /* 10325476 -- swap bit pairs */
+  z = SWIZZLE(t, 0x55555555, 1);       /* 01234567 -- swap adjacent bits */
+#  undef SWIZZLE
+#endif
+  return (z);
+}
+
+static void arm64_pmull_mktable(const gcm_params *p,
+                               uint32 *ktab, const uint32 *k)
+{
+  unsigned n = p->n;
+  uint32 *t;
+
+  /* We just need to store the value in a way which is convenient for the
+   * assembler code to read back.  That involves two transformations:
+   *
+   *   * firstly, reversing the order of the bits in each byte; and,
+   *
+   *   * secondly, storing two copies of each 64-bit chunk.
+   *
+   * Note that, in this case, we /want/ the little-endian byte order of GCM,
+   * so endianness-swapping happens in the big-endian case.
+   */
+
+  t = ktab;
+  if (p->f&GCMF_SWAP) {
+    while (n >= 2) {
+      t[0] = t[2] = rbit32(k[0]);
+      t[1] = t[3] = rbit32(k[1]);
+      t += 4; k += 2; n -= 2;
+    }
+    if (n) { t[0] = t[2] = rbit32(k[0]); t[1] = t[3] = 0; }
+  } else {
+    while (n >= 2) {
+      t[0] = t[2] = ENDSWAP32(rbit32(k[0]));
+      t[1] = t[3] = ENDSWAP32(rbit32(k[1]));
+      t += 4; k += 2; n -= 2;
+    }
+    if (n) { t[0] = t[2] = ENDSWAP32(rbit32(k[0])); t[1] = t[3] = 0; }
+  }
+}
+#endif
+
+CPU_DISPATCH(EMPTY, EMPTY, void, gcm_mktable,
+            (const gcm_params *p, uint32 *ktab, const uint32 *k),
+            (p, ktab, k),
+            pick_mktable, simple_mktable)
+
+static gcm_mktable__functype *pick_mktable(void)
+{
+#if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(gcm_mktable, pclmul_mktable,
+                    cpu_feature_p(CPUFEAT_X86_SSSE3) &&
+                    cpu_feature_p(CPUFEAT_X86_PCLMUL));
+#endif
+#if CPUFAM_ARMEL
+  DISPATCH_PICK_COND(gcm_mktable, arm_crypto_mktable,
+                    cpu_feature_p(CPUFEAT_ARM_PMULL));
+#endif
+#if CPUFAM_ARM64
+  DISPATCH_PICK_COND(gcm_mktable, arm64_pmull_mktable,
+                    cpu_feature_p(CPUFEAT_ARM_PMULL));
+#endif
+  DISPATCH_PICK_FALLBACK(gcm_mktable, simple_mktable);
+}
+
+/* --- @recover_k@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *k@ = block-sized vector in which to store %$k$%
+ *             @const uint32 *ktab@ = the table encoding %$k$%
+ *
+ * Returns:    ---
+ *
+ * Use:                Recovers %$k$%, the secret from which @ktab@ was by
+ *             @gcm_mktable@, from the table, and stores it in internal
+ *             (big-endian) form in @k@.
+ */
+
+static void simple_recover_k(const gcm_params *p,
+                            uint32 *k, const uint32 *ktab)
+{
+  unsigned i;
+
+  /* If the blockcipher is big-endian, then the key is simply in the first
+   * table element, in the right format.  If the blockcipher is little-endian
+   * then it's in element 24, and the bytes need swapping.
+   */
+
+  if (!(p->f&GCMF_SWAP)) for (i = 0; i < p->n; i++) k[i] = ktab[i];
+  else for (i = 0; i < p->n; i++) k[i] = ENDSWAP32(ktab[24*p->n + i]);
+}
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+static void pclmul_recover_k(const gcm_params *p,
+                            uint32 *k, const uint32 *ktab)
+{
+  unsigned n = p->n;
+  unsigned nz;
+  const uint32 *t;
+
+  /* The representation is already independent of the blockcipher endianness.
+   * We need to compensate for padding, and reorder the words.
+   */
+
+  if (n == 3) nz = 1; else nz = 0;
+  t = ktab + n + nz;
+  while (n--) *k++ = *--t;
+}
+#endif
+
+#if CPUFAM_ARMEL
+static void arm_crypto_recover_k(const gcm_params *p,
+                                uint32 *k, const uint32 *ktab)
+{
+  unsigned n = p->n;
+  const uint32 *t;
+
+  /* The representation is already independent of the blockcipher endianness.
+   * We only need to reorder the words.
+   */
+
+  t = ktab;
+  while (n >= 2) { k[1] = t[0]; k[0] = t[1]; t += 2; k += 2; n -= 2; }
+  if (n) k[0] = t[1];
+}
+#endif
+
+#if CPUFAM_ARM64
+static void arm64_pmull_recover_k(const gcm_params *p,
+                                 uint32 *k, const uint32 *ktab)
+{
+  unsigned n = p->n;
+  const uint32 *t;
+
+  /* The representation is already independent of the blockcipher endianness.
+   * We need to skip the duplicate pieces, and unscramble the bytes.
+   */
+
+  t = ktab;
+  while (n >= 2) {
+    k[0] = ENDSWAP32(rbit32(t[0]));
+    k[1] = ENDSWAP32(rbit32(t[1]));
+    t += 4; k += 2; n -= 2;
+  }
+  if (n) k[0] = ENDSWAP32(rbit32(t[0]));
+}
+#endif
+
+CPU_DISPATCH(static, EMPTY, void, recover_k,
+            (const gcm_params *p, uint32 *k, const uint32 *ktab),
+            (p, k, ktab),
+            pick_recover_k, simple_recover_k)
+
+static recover_k__functype *pick_recover_k(void)
+{
+#if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(recover_k, pclmul_recover_k,
+                    cpu_feature_p(CPUFEAT_X86_SSSE3) &&
+                    cpu_feature_p(CPUFEAT_X86_PCLMUL));
+#endif
+#if CPUFAM_ARMEL
+  DISPATCH_PICK_COND(recover_k, arm_crypto_recover_k,
+                    cpu_feature_p(CPUFEAT_ARM_PMULL));
+#endif
+#if CPUFAM_ARM64
+  DISPATCH_PICK_COND(recover_k, arm64_pmull_recover_k,
+                    cpu_feature_p(CPUFEAT_ARM_PMULL));
+#endif
+  DISPATCH_PICK_FALLBACK(recover_k, simple_recover_k);
+}
+
+/* --- @gcm_mulk_N{b,l}@ --- *
+ *
+ * Arguments:  @uint32 *a@ = accumulator to multiply
+ *             @const uint32 *ktab@ = table constructed by @gcm_mktable@
+ *
+ * Returns:    ---
+ *
+ * Use:                Multiply @a@ by @k@ (implicitly represented in @ktab@),
+ *             updating @a@ in-place.  There are separate functions for each
+ *             supported block size and endianness because this is the
+ *             function whose performance actually matters.
+ */
+
+#if CPUFAM_X86 || CPUFAM_AMD64
+#  define DECL_MULK_X86ISH(var) extern gcm_mulk_##var##__functype      \
+  gcm_mulk_##var##_x86ish_pclmul_avx,                                  \
+  gcm_mulk_##var##_x86ish_pclmul;
+#  define PICK_MULK_X86ISH(var) do {                                   \
+  DISPATCH_PICK_COND(gcm_mulk_##var, gcm_mulk_##var##_x86ish_pclmul_avx, \
+                    cpu_feature_p(CPUFEAT_X86_AVX) &&                  \
+                    cpu_feature_p(CPUFEAT_X86_PCLMUL) &&               \
+                    cpu_feature_p(CPUFEAT_X86_SSSE3));                 \
+  DISPATCH_PICK_COND(gcm_mulk_##var, gcm_mulk_##var##_x86ish_pclmul,   \
+                    cpu_feature_p(CPUFEAT_X86_PCLMUL) &&               \
+                    cpu_feature_p(CPUFEAT_X86_SSSE3));                 \
+} while (0)
+#else
+#  define DECL_MULK_X86ISH(var)
+#  define PICK_MULK_X86ISH(var) do ; while (0)
+#endif
+
+#if CPUFAM_ARMEL
+#  define DECL_MULK_ARM(var)                                           \
+  extern gcm_mulk_##var##__functype gcm_mulk_##var##_arm_crypto;
+#  define PICK_MULK_ARM(var) do {                                      \
+  DISPATCH_PICK_COND(gcm_mulk_##var, gcm_mulk_##var##_arm_crypto,      \
+                    cpu_feature_p(CPUFEAT_ARM_PMULL));                 \
+} while (0)
+#else
+#  define DECL_MULK_ARM(var)
+#  define PICK_MULK_ARM(var) do ; while (0)
+#endif
+
+#if CPUFAM_ARM64
+#  define DECL_MULK_ARM64(var)                                         \
+  extern gcm_mulk_##var##__functype gcm_mulk_##var##_arm64_pmull;
+#  define PICK_MULK_ARM64(var) do {                                    \
+  DISPATCH_PICK_COND(gcm_mulk_##var, gcm_mulk_##var##_arm64_pmull,     \
+                    cpu_feature_p(CPUFEAT_ARM_PMULL));                 \
+} while (0)
+#else
+#  define DECL_MULK_ARM64(var)
+#  define PICK_MULK_ARM64(var) do ; while (0)
+#endif
+
+#define DEF_MULK(nbits)                                                        \
+                                                                       \
+CPU_DISPATCH(EMPTY, EMPTY, void, gcm_mulk_##nbits##b,                  \
+            (uint32 *a, const uint32 *ktab), (a, ktab),                \
+            pick_mulk_##nbits##b, simple_mulk_##nbits)                 \
+CPU_DISPATCH(EMPTY, EMPTY, void, gcm_mulk_##nbits##l,                  \
+            (uint32 *a, const uint32 *ktab), (a, ktab),                \
+            pick_mulk_##nbits##l, simple_mulk_##nbits)                 \
+                                                                       \
+static void simple_mulk_##nbits(uint32 *a, const uint32 *ktab)         \
+{                                                                      \
+  uint32 m, t;                                                         \
+  uint32 z[nbits/32];                                                  \
+  unsigned i, j, k;                                                    \
+                                                                       \
+  for (i = 0; i < nbits/32; i++) z[i] = 0;                             \
+                                                                       \
+  for (i = 0; i < nbits/32; i++) {                                     \
+    t = a[i];                                                          \
+    for (j = 0; j < 32; j++) {                                         \
+      m = -((t >> 31)&1u);                                             \
+      for (k = 0; k < nbits/32; k++) z[k] ^= *ktab++&m;                        \
+      t <<= 1;                                                         \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  for (i = 0; i < nbits/32; i++) a[i] = z[i];                          \
+}                                                                      \
+                                                                       \
+DECL_MULK_X86ISH(nbits##b)                                             \
+DECL_MULK_ARM(nbits##b)                                                        \
+DECL_MULK_ARM64(nbits##b)                                              \
+static gcm_mulk_##nbits##b##__functype *pick_mulk_##nbits##b(void)     \
+{                                                                      \
+  PICK_MULK_X86ISH(nbits##b);                                          \
+  PICK_MULK_ARM(nbits##b);                                             \
+  PICK_MULK_ARM64(nbits##b);                                           \
+  DISPATCH_PICK_FALLBACK(gcm_mulk_##nbits##b, simple_mulk_##nbits);    \
+}                                                                      \
+                                                                       \
+DECL_MULK_X86ISH(nbits##l)                                             \
+DECL_MULK_ARM(nbits##l)                                                        \
+DECL_MULK_ARM64(nbits##l)                                              \
+static gcm_mulk_##nbits##l##__functype *pick_mulk_##nbits##l(void)     \
+{                                                                      \
+  PICK_MULK_X86ISH(nbits##l);                                          \
+  PICK_MULK_ARM(nbits##l);                                             \
+  PICK_MULK_ARM64(nbits##l);                                           \
+  DISPATCH_PICK_FALLBACK(gcm_mulk_##nbits##l, simple_mulk_##nbits);    \
+}
+
+GCM_WIDTHS(DEF_MULK)
+
+#define GCM_MULK_CASE(nbits)                                           \
+  case nbits/32:                                                       \
+    if (_f&GCMF_SWAP) gcm_mulk_##nbits##l(_a, _ktab);                  \
+    else gcm_mulk_##nbits##b(_a, _ktab);                               \
+    break;
+#define MULK(n, f, a, ktab) do {                                       \
+  uint32 *_a = (a); const uint32 *_ktab = (ktab);                      \
+  unsigned _f = (f);                                                   \
+  switch (n) {                                                         \
+    GCM_WIDTHS(GCM_MULK_CASE)                                          \
+    default: abort();                                                  \
+  }                                                                    \
+} while (0)
+
+/*----- Other utilities ---------------------------------------------------*/
+
+/* --- @putlen@ --- *
+ *
+ * Arguments:  @octet *p@ = pointer to output buffer
+ *             @unsigned w@ = size of output buffer
+ *             @unsigned blksz@ = block size (assumed fairly small)
+ *             @unsigned long nblocks@ = number of blocks
+ *             @unsigned nbytes@ = tail size in bytes (assumed small)
+ *
+ * Returns:    ---
+ *
+ * Use:                Store the overall length in %$\emph{bits}$% (i.e.,
+ *             @3*(nblocks*blksz + nbytes)@ in big-endian form in the
+ *             buffer @p@.
+ */
+
+static void putlen(octet *p, unsigned w, unsigned blksz,
+                  unsigned long nblocks, unsigned nbytes)
+{
+  unsigned long nblo = nblocks&((1ul << (ULONG_BITS/2)) - 1),
+    nbhi = nblocks >> ULONG_BITS/2;
+  unsigned long nlo = nblo*blksz + nbytes, nhi = nbhi*blksz;
+
+  /* This is fiddly.  Split @nblocks@, which is the big number, into high and
+   * low halves, multiply those separately by @blksz@, propagate carries, and
+   * then multiply by eight.
+   */
+  nhi += nlo >> ULONG_BITS/2;
+  nlo &= (1ul << (ULONG_BITS/2)) - 1;
+  nlo <<= 3;
+
+  /* Now write out the size, feeding bits in from @nhi@ as necessary. */
+  p += w;
+  while (w--) {
+    *--p = U8(nlo);
+    nlo = (nlo >> 8) | ((nhi&0xff) << (ULONG_BITS/2 - 5));
+    nhi >>= 8;
+  }
+}
+
+/* --- @mix@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *a@ = GHASH accumulator
+ *             @const octet *q@ = pointer to an input block
+ *             @const uint32 *ktab@ = multiplication table, built by
+ *                     @gcm_mktable@
+ *
+ * Returns:    ---
+ *
+ * Use:                Fold the block @q@ into the GHASH accumulator.  The
+ *             calculation is %$a' = k (a + q)$%.
+ */
+
+static void mix(const gcm_params *p, uint32 *a,
+               const octet *q, const uint32 *ktab)
+{
+  unsigned i;
+
+  if (p->f&GCMF_SWAP)
+    for (i = 0; i < p->n; i++) { a[i] ^= LOAD32_L(q); q += 4; }
+  else
+    for (i = 0; i < p->n; i++) { a[i] ^= LOAD32_B(q); q += 4; }
+  MULK(p->n, p->f, a, ktab);
+}
+
+/* --- @gcm_ghashdone@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *a@ = GHASH accumulator
+ *             @const uint32 *ktab@ = multiplication table, built by
+ *                     @gcm_mktable@
+ *             @unsigned long xblocks, yblocks@ = number of whole blocks in
+ *                     the two inputs
+ *             @unsigned xbytes, ybytes@ = number of trailing bytes in the
+ *                     two inputs
+ *
+ * Returns:    ---
+ *
+ * Use:                Finishes a GHASH operation by appending the appropriately
+ *             encoded lengths of the two constituent messages.
+ */
+
+void gcm_ghashdone(const gcm_params *p, uint32 *a, const uint32 *ktab,
+                  unsigned long xblocks, unsigned xbytes,
+                  unsigned long yblocks, unsigned ybytes)
+{
+  octet b[4*GCM_NMAX];
+  unsigned w = p->n < 3 ? 4*p->n : 2*p->n;
+
+  /* Construct the encoded lengths.  Note that smaller-block versions of GCM
+   * encode the lengths in separate blocks.  GCM is only officially defined
+   * for 64- and 128-bit blocks; I've placed the cutoff somewhat arbitrarily
+   * at 96 bits.
+   */
+  putlen(b,     w, 4*p->n, xblocks, xbytes);
+  putlen(b + w, w, 4*p->n, yblocks, ybytes);
+
+  /* Feed the lengths into the accumulator. */
+  mix(p, a, b, ktab);
+  if (p->n < 3) mix(p, a, b + w, ktab);
+}
+
+/* --- @gcm_concat@ --- *
+ *
+ * Arguments:  @const gcm_params *p@ = pointer to the parameters
+ *             @uint32 *z@ = GHASH accumulator for suffix, updated
+ *             @const uint32 *x@ = GHASH accumulator for prefix
+ *             @const uint32 *ktab@ = multiplication table, built by
+ *                     @gcm_mktable@
+ *             @unsigned long n@ = length of suffix in whole blocks
+ *
+ * Returns:    ---
+ *
+ * Use:                On entry, @x@ and @z@ are the results of hashing two strings
+ *             %$a$% and %$b$%, each a whole number of blocks long; in
+ *             particular, %$b$% is @n@ blocks long.  On exit, @z@ is
+ *             updated to be the hash of %$a \cat b$%.
+ */
+
+void gcm_concat(const gcm_params *p, uint32 *z, const uint32 *x,
+               const uint32 *ktab, unsigned long n)
+{
+  uint32 t[GCM_NMAX], u[GCM_NMAX];
+  unsigned i, j;
+
+  if (!n) {
+    /* If @n@ is zero, then there's not much to do.  The mathematics
+     * (explained below) still works, but the code takes a shortcut which
+     * doesn't handle this case: so set %$z' = z + x k^n = z + x$%.
+     */
+
+    for (j = 0; j < p->n; j++) z[j] ^= x[j];
+  } else {
+    /* We have %$x = a_0 t^m + \cdots + a_{m-2} t^2 + a_{m-1} t$% and
+     * %$z = b_0 t^n + \cdots + b_{n-2} t^2 + b_{n-1} t$%.  What we'd like is
+     * the hash of %$a \cat b$%, which is %$z + x k^n$%.
+     *
+     * The first job, then, is to calculate %$k^n$%, and for this we use a
+     * simple left-to-right square-and-multiply algorithm.  There's no need
+     * to keep %$n$% secret here.
+     */
+
+    /* Start by retrieving %$k$% from the table, and convert it to big-endian
+     * form.
+     */
+    recover_k(p, u, ktab);
+
+    /* Now calculate %$k^n$%. */
+    i = ULONG_BITS;
+#define BIT (1ul << (ULONG_BITS - 1))
+    while (!(n&BIT)) { n <<= 1; i--; }
+    n <<= 1; i--; for (j = 0; j < p->n; j++) t[j] = u[j];
+    while (i--) { mul(p, t, t, t); if (n&BIT) mul(p, t, t, u); n <<= 1; }
+#undef BIT
+
+    /* Next, calculate %$x k^n$%.  If we're using a little-endian convention
+     * then we must convert %$x$%; otherwise we can just use it in place.
+     */
+    if (!(p->f&GCMF_SWAP))
+      mul(p, t, t, x);
+    else {
+      for (j = 0; j < p->n; j++) u[j] = ENDSWAP32(x[j]);
+      mul(p, t, t, u);
+    }
+
+    /* Finally, add %$x k^n$% onto %$z$%, converting back to little-endian if
+     * necessary.
+     */
+    if (!(p->f&GCMF_SWAP)) for (j = 0; j < p->n; j++) z[j] ^= t[j];
+    else for (j = 0; j < p->n; j++) z[j] ^= ENDSWAP32(t[j]);
+  }
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+static void report_failure(const char *test, unsigned nbits,
+                          const char *ref, dstr v[], dstr *d)
+{
+  printf("test %s failed (nbits = %u)", test, nbits);
+  printf("\n\tx  = "); type_hex.dump(&v[0], stdout);
+  printf("\n\ty  = "); type_hex.dump(&v[1], stdout);
+  printf("\n\tz  = "); type_hex.dump(&v[2], stdout);
+  printf("\n\t%s' = ", ref); type_hex.dump(d, stdout);
+  putchar('\n');
+}
+
+static void mulk(unsigned nbits, unsigned f, uint32 *x, const uint32 *ktab)
+  { MULK(nbits/32, f, x, ktab); }
+
+static int test_mul(uint32 poly, dstr v[])
+{
+  uint32 x[GCM_NMAX], y[GCM_NMAX], z[GCM_NMAX], ktab[32*GCM_NMAX*GCM_NMAX];
+  gcm_params p;
+  dstr d = DSTR_INIT;
+  unsigned i, nbits;
+  int ok = 1;
+  enum { I_x, I_y, I_z };
+
+  nbits = 8*v[0].len; p.f = 0; p.n = nbits/32; p.poly = poly;
+  dstr_ensure(&d, nbits/8); d.len = nbits/8;
+
+#define LOADXY(E) do {                                                 \
+  for (i = 0; i < nbits/32; i++) {                                     \
+    x[i] = LOAD32_##E(v[I_x].buf + 4*i);                               \
+    y[i] = LOAD32_##E(v[I_y].buf + 4*i);                               \
+  }                                                                    \
+} while (0)
+
+#define INITZ(x) do {                                                  \
+  for (i = 0; i < nbits/32; i++) z[i] = (x)[i];                                \
+} while (0)
+
+#define CHECK(E, what, ref) do {                                       \
+  for (i = 0; i < nbits/32; i++) STORE32_##E(d.buf + 4*i, z[i]);       \
+  if (memcmp(d.buf, v[I_##ref].buf, nbits/8) != 0)                     \
+    { ok = 0; report_failure(what, nbits, #ref, v, &d); }              \
+} while (0)
+
+#define TEST_PREP_1(E, x, y, what) do {                                        \
+  gcm_mktable(&p, ktab, y);                                            \
+  recover_k(&p, z, ktab); CHECK(B, "mktable/recover_k (" #y ")", y);   \
+  INITZ(x); mulk(nbits, p.f, z, ktab); CHECK(E, what " (k = " #y ")", z); \
+} while (0)
+
+#define TEST_PREP(E, what) do {                                                \
+  TEST_PREP_1(E, x, y, what);                                          \
+  TEST_PREP_1(E, y, x, what);                                          \
+} while (0)
+
+  /* First, test plain multiply. */
+  LOADXY(B); mul(&p, z, x, y); CHECK(B, "gcm_mul", z);
+
+  /* Next, test big-endian prepared key. */
+  LOADXY(B); TEST_PREP(B, "gcm_kmul_b");
+
+  /* Finally, test little-endian prepared key. */
+  p.f = GCMF_SWAP; LOADXY(L);
+  TEST_PREP(L, "gcm_kmul_l");
+
+#undef LOADXY
+#undef INITZ
+#undef CHECK
+#undef TEST_PREP_1
+#undef TEST_PREP
+
+  /* All done. */
+  return (ok);
+}
+
+#define TEST(nbits)                                                    \
+static int test_mul_##nbits(dstr v[])                                  \
+  { return (test_mul(GCM_POLY_##nbits, v)); }
+GCM_WIDTHS(TEST)
+#undef TEST
+
+static test_chunk defs[] = {
+#define TEST(nbits)                                                    \
+  { "gcm-mul" #nbits, test_mul_##nbits,                                        \
+    { &type_hex, &type_hex, &type_hex, 0 } },
+GCM_WIDTHS(TEST)
+#undef TEST
+  { 0, 0, { 0 } }
+};
+
+int main(int argc,  char *argv[])
+{
+  ego(argv[0]);
+  test_run(argc, argv, defs, SRCDIR"/t/gcm");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/symm/gcm.h b/symm/gcm.h
new file mode 100644 (file)
index 0000000..d3e6d03
--- /dev/null
@@ -0,0 +1,308 @@
+/* -*-c-*-
+ *
+ * The GCM authenticated encryption mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Notes on GCM ------------------------------------------------------*
+ *
+ * The name is short for `Galois Counter Mode'.  GCM was designed in 2005 by
+ * David McGrew and John Viega as a fast, patent-free authenticated
+ * encryption scheme; and it's specified by NIST in SP800-38D.  It combines
+ * counter-mode encryption with a Carter--Wegman authenticator based on a
+ * polynomial hash over %$\gf{2^{128}}%, so it needs only one blockcipher
+ * application per message block, together with a multiplication by a
+ * constant in the finite field.  GCM is essentially the winner in the
+ * authenticated-encryption-mode competition, to the extent that Intel and
+ * ARM both added instructions to their architectures to accelerate it.
+ *
+ * GCM allows arbitrary-sized nonces, though it's happiest if the nonce is 32
+ * bits shorter than the block size, leaving a fixed-size block counter in
+ * the low 32 bits.  It permits header data to be processed independently of
+ * the message, though doing this requires some slightly fiddly algebra and
+ * most implementations don't allow callers to take advantage of this.
+ *
+ * One downside is that the field multiplication is inefficient in software.
+ * Back in 2005 it was assumed that implementors would use large tables, but
+ * that leaks the authentication secret through the processor cache.  This
+ * implementation runs in constant time, but the penalty is that, without
+ * dedicated processor support, it's much slower than an extra blockcipher
+ * application would have been.
+ *
+ * Another downside is that, while GCM came with a security proof, it was
+ * subtly incorrect in a few ways which mean that its concrete security is
+ * significantly less than one would expect.
+ *
+ * If interoperability isn't a concern, then OCB3 is probably a better
+ * choice; if the OCB patent situation is also worrying, then EAX is likely
+ * preferable.
+ */
+
+#ifndef CATACOMB_GCM_H
+#define CATACOMB_GCM_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @GCM_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates declarations for GCM authenticated-encryption mode.
+ */
+
+#define GCM_DECL(PRE, pre)                                             \
+                                                                       \
+typedef struct pre##_gcmkey {                                          \
+  pre##_ctx ctx;                       /* Block cipher key */          \
+  uint32 ktab[32*PRE##_BLKSZ*PRE##_BLKSZ]; /* Multiplication table */  \
+} pre##_gcmkey;                                                                \
+                                                                       \
+typedef struct pre##_gcmaadctx {                                       \
+  pre##_gcmkey k;                      /* Underlying key */            \
+  uint32 a[PRE##_BLKSZ/4];             /* GHASH accumulator */         \
+  octet b[PRE##_BLKSZ];                        /* Input buffer */              \
+  unsigned off;                                /* Length of stuff in buffer */ \
+  unsigned long len;                   /* Number of blocks so far */   \
+} pre##_gcmaadctx;                                                     \
+                                                                       \
+typedef struct pre##_gcmctx {                                          \
+  /* The buffer is split into two portions.  The first N octets hold a \
+   * chunk of ciphertext, which will be fed into the OMAC calculation; \
+   * the remaining BLKSZ - N octets hold E_K(C), which is the XOR mask \
+   * to apply to the plaintext or ciphertext.                          \
+   */                                                                  \
+  pre##_gcmkey k;                      /* Underlying key */            \
+  uint32 c[PRE##_BLKSZ/4];             /* Current counter value */     \
+  uint32 c0[PRE##_BLKSZ/4];            /* Initial counter */           \
+  uint32 a[PRE##_BLKSZ];               /* GHASH accumulator */         \
+  octet b[PRE##_BLKSZ];                        /* Ciphertext/mask buffer */    \
+  unsigned off;                                /* Crossover point in buffer */ \
+  unsigned long len;                   /* Number of blocks so far */   \
+} pre##_gcmctx;                                                                \
+                                                                       \
+extern const octet pre##_gcmnoncesz[], pre##_gcmtagsz[];               \
+                                                                       \
+/* --- @pre_gcmsetkey@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_gcmkey *key@ = pointer to key block to fill in     \
+ *             @const void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an GCM key block.                           \
+ */                                                                    \
+                                                                       \
+extern void pre##_gcmsetkey(pre##_gcmkey */*key*/,                     \
+                           const void */*k*/, size_t /*ksz*/);         \
+                                                                       \
+/* --- @pre_gcmaadinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmaadctx *aad@ = pointer to AAD context           \
+ *             @const pre_gcmkey *key@ = pointer to key block          \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an GCM AAD (`additional authenticated       \
+ *             data') context associated with a given key.  AAD        \
+ *             contexts can be copied and/or reused, saving time if    \
+ *             the AAD for a number of messages has a common prefix.   \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around, though        \
+ *             usually there'll at least be another copy in some GCM   \
+ *             operation context because the AAD on its own isn't much \
+ *             good.                                                   \
+ */                                                                    \
+                                                                       \
+extern void pre##_gcmaadinit(pre##_gcmaadctx */*aad*/,                 \
+                            const pre##_gcmkey */*key*/);              \
+                                                                       \
+/* --- @pre_gcmaadhash@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmaadctx *aad@ = pointer to AAD context           \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.                             \
+ */                                                                    \
+                                                                       \
+extern void pre##_gcmaadhash(pre##_gcmaadctx */*aad*/,                 \
+                            const void */*p*/, size_t /*sz*/);         \
+                                                                       \
+/* --- @pre_gcminit@ --- *                                             \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM context              \
+ *             @const pre_gcmkey *key@ = pointer to key block          \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initialize an GCM operation context with a given key.   \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+extern void pre##_gcminit(pre##_gcmctx */*ctx*/,                       \
+                         const pre##_gcmkey */*k*/,                    \
+                         const void */*n*/, size_t /*nsz*/);           \
+                                                                       \
+/* --- @pre_gcmreinit@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM context              \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Reinitialize an GCM operation context, changing the     \
+ *             nonce.                                                  \
+ */                                                                    \
+                                                                       \
+extern void pre##_gcmreinit(pre##_gcmctx */*ctx*/,                     \
+                           const void */*n*/, size_t /*nsz*/);         \
+                                                                       \
+/* --- @pre_gcmencrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM operation context    \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For GCM, we always write a ciphertext chunk the same    \
+ *             size as the plaintext.  The messing about with @buf@    \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+extern int pre##_gcmencrypt(pre##_gcmctx */*ctx*/,                     \
+                           const void */*src*/, size_t /*sz*/,         \
+                           buf */*dst*/);                              \
+                                                                       \
+/* --- @pre_gcmdecrypt@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to GCM operation context    \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             For GCM, we always write a plaintext chunk the same     \
+ *             size as the ciphertext.  The messing about with @buf@   \
+ *             objects makes the interface consistent with other AEAD  \
+ *             schemes which can't do this.                            \
+ */                                                                    \
+                                                                       \
+extern int pre##_gcmdecrypt(pre##_gcmctx */*ctx*/,                     \
+                           const void */*src*/, size_t /*sz*/,         \
+                           buf */*dst*/);                              \
+                                                                       \
+/* --- @pre_gcmencryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to an GCM context           \
+ *             @const pre_gcmaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an GCM encryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  GCM doesn't buffer ciphertext, but \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+extern int pre##_gcmencryptdone(pre##_gcmctx */*ctx*/,                 \
+                               const pre##_gcmaadctx */*aad*/,         \
+                               buf */*dst*/,                           \
+                               void */*tag*/, size_t /*tsz*/);         \
+                                                                       \
+/* --- @pre_gcmdecryptdone@ --- *                                      \
+ *                                                                     \
+ * Arguments:  @pre_gcmctx *ctx@ = pointer to an GCM context           \
+ *             @const pre_gcmaadctx *aad@ = pointer to AAD context, or \
+ *                     null                                            \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an GCM decryption operation.  The @aad@       \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  GCM doesn't buffer plaintext, but  \
+ *             the output buffer is provided anyway for consistency    \
+ *             with other AEAD schemes which don't have this property; \
+ *             the function will fail if the output buffer is broken.  \
+ */                                                                    \
+                                                                       \
+extern int pre##_gcmdecryptdone(pre##_gcmctx */*ctx*/,                 \
+                               const pre##_gcmaadctx */*aad*/,         \
+                               buf */*dst*/,                           \
+                               const void */*tag*/, size_t /*tsz*/);   \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+extern const gcaead pre##_gcm;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index eb3cd75..3d0c117 100644 (file)
 
 #include <mLib/bits.h>
 
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
 /*----- Macros ------------------------------------------------------------*/
 
 /* --- @HASH_BUFFER@ --- *
 #define HASH_BUFFER(PRE, pre, ictx, ibuf, isz) do {                    \
   pre##_ctx *_bctx = (ictx);                                           \
   size_t _bsz = (isz);                                                 \
-  const octet *_bbuf = (octet *)(ibuf);                                        \
+  const octet *_bbuf = (octet *)(ibuf), *_p;                           \
+  static const rsvr_policy _pol = { 0, PRE##_BUFSZ, PRE##_BUFSZ };     \
+  uint32 _l, _h;                                                       \
+  rsvr_state _st;                                                      \
                                                                        \
   /* --- Add on the size done so far --- *                             \
    *                                                                   \
    * how many bits you've actually got.                                        \
    */                                                                  \
                                                                        \
-  {                                                                    \
-    uint32 _l = U32(_bsz);                                             \
-    uint32 _h = ((_bsz & ~(size_t)MASK32) >> 16) >> 16;                        \
-    _bctx->nh += _h;                                                   \
-    _bctx->nl += _l;                                                   \
-    if (_bctx->nl < _l || _bctx->nl & ~(uint32)MASK32)                 \
-      _bctx->nh++;                                                     \
-  }                                                                    \
-                                                                       \
-  /* --- Handle very small contributions --- */                                \
-                                                                       \
-  if (_bctx->off + _bsz < PRE##_BUFSZ) {                               \
-    memcpy(_bctx->buf + _bctx->off, _bbuf, _bsz);                      \
-    _bctx->off += _bsz;                                                        \
-  } else {                                                             \
-                                                                       \
-    /* --- Handle an initial partial buffer --- */                     \
+  _l = U32(_bsz); _h = ((_bsz & ~(size_t)MASK32) >> 16) >> 16;         \
+  _bctx->nl += _l; if (_bctx->nl < _l || _bctx->nl & ~(uint32)MASK32) _h++; \
+  _bctx->nh += _h;                                                     \
                                                                        \
-    if (_bctx->off) {                                                  \
-      size_t s = PRE##_BUFSZ - _bctx->off;                             \
-      memcpy(_bctx->buf + _bctx->off, _bbuf, s);                       \
-      pre##_compress(_bctx, _bctx->buf);                               \
-      _bsz -= s; _bbuf += s;                                           \
-    }                                                                  \
-                                                                       \
-    /* --- Do whole buffers while we can --- */                                \
-                                                                       \
-    while (_bsz >= PRE##_BUFSZ) {                                      \
-      pre##_compress(_bctx, _bbuf);                                    \
-      _bsz -= PRE##_BUFSZ; _bbuf += PRE##_BUFSZ;                       \
-    }                                                                  \
-                                                                       \
-    /* --- And wrap up at the end --- */                               \
+  /* --- Accumulate the input data --- */                              \
                                                                        \
-    if (_bsz)                                                          \
-      memcpy(_bctx->buf, _bbuf, _bsz);                                 \
-    _bctx->off = _bsz;                                                 \
-  }                                                                    \
+  rsvr_setup(&_st, &_pol, _bctx->buf, &_bctx->off, _bbuf, _bsz);       \
+  RSVR_DO(&_st) while ((_p = RSVR_NEXT(&_st, PRE##_BUFSZ)) != 0)       \
+    pre##_compress(_bctx, _p);                                         \
 } while (0)
 
 /* --- @HASH_PAD@ --- *
index 72bd126..e3f12ce 100644 (file)
@@ -208,9 +208,7 @@ void pre##_macinit(pre##_macctx *ctx, const pre##_mackey *key)              \
  */                                                                    \
                                                                        \
 void pre##_machash(pre##_macctx *ctx, const void *buf, size_t sz)      \
-{                                                                      \
-  pre##_hash(&ctx->ctx, buf, sz);                                      \
-}                                                                      \
+  { pre##_hash(&ctx->ctx, buf, sz); }                                  \
                                                                        \
 /* --- @pre_macdone@ --- *                                             \
  *                                                                     \
index 10a3516..d58bc6f 100644 (file)
@@ -338,25 +338,25 @@ static void keccak1600_round(keccak1600_state *z,
    * result to Z.
    */
 
-  lane b[5], c[5], d[5], t;
+  lane c[5], d[5], t;
 
   /* Theta, first step: calculate the column parities. */
 #define COLPARITY(j) do {                                              \
-          c[j] =      x->S[I(j, 0)];                                   \
-  XOR_LANE(c[j], c[j], x->S[I(j, 1)]);                                 \
-  XOR_LANE(c[j], c[j], x->S[I(j, 2)]);                                 \
-  XOR_LANE(c[j], c[j], x->S[I(j, 3)]);                                 \
-  XOR_LANE(c[j], c[j], x->S[I(j, 4)]);                                 \
+          d[j] =      x->S[I(j, 0)];                                   \
+  XOR_LANE(d[j], d[j], x->S[I(j, 1)]);                                 \
+  XOR_LANE(d[j], d[j], x->S[I(j, 2)]);                                 \
+  XOR_LANE(d[j], d[j], x->S[I(j, 3)]);                                 \
+  XOR_LANE(d[j], d[j], x->S[I(j, 4)]);                                 \
 } while (0)
   COLPARITY(0); COLPARITY(1); COLPARITY(2); COLPARITY(3); COLPARITY(4);
 #undef COLPARITY
 
   /* Theta, second step: calculate the combined effect. */
-  ROTL_LANE(d[0], c[1], 1); XOR_LANE(d[0], d[0], c[4]);
-  ROTL_LANE(d[1], c[2], 1); XOR_LANE(d[1], d[1], c[0]);
-  ROTL_LANE(d[2], c[3], 1); XOR_LANE(d[2], d[2], c[1]);
-  ROTL_LANE(d[3], c[4], 1); XOR_LANE(d[3], d[3], c[2]);
-  ROTL_LANE(d[4], c[0], 1); XOR_LANE(d[4], d[4], c[3]);
+  ROTL_LANE(c[0], d[1], 1); XOR_LANE(c[0], c[0], d[4]);
+  ROTL_LANE(c[1], d[2], 1); XOR_LANE(c[1], c[1], d[0]);
+  ROTL_LANE(c[2], d[3], 1); XOR_LANE(c[2], c[2], d[1]);
+  ROTL_LANE(c[3], d[4], 1); XOR_LANE(c[3], c[3], d[2]);
+  ROTL_LANE(c[4], d[0], 1); XOR_LANE(c[4], c[4], d[3]);
 
   /* Now we work plane by plane through the output.  To do this, we must undo
    * the pi transposition.  Pi maps (x', y') = (y, 2 x + 3 y), so y = x', and
@@ -365,18 +365,18 @@ static void keccak1600_round(keccak1600_state *z,
 #define THETA_RHO(i0, i1, i2, i3, i4) do {                             \
                                                                        \
   /* First, theta. */                                                  \
-  XOR_LANE(b[0], x->S[I(i0, 0)], d[i0]);                               \
-  XOR_LANE(b[1], x->S[I(i1, 1)], d[i1]);                               \
-  XOR_LANE(b[2], x->S[I(i2, 2)], d[i2]);                               \
-  XOR_LANE(b[3], x->S[I(i3, 3)], d[i3]);                               \
-  XOR_LANE(b[4], x->S[I(i4, 4)], d[i4]);                               \
+  XOR_LANE(d[0], x->S[I(i0, 0)], c[i0]);                               \
+  XOR_LANE(d[1], x->S[I(i1, 1)], c[i1]);                               \
+  XOR_LANE(d[2], x->S[I(i2, 2)], c[i2]);                               \
+  XOR_LANE(d[3], x->S[I(i3, 3)], c[i3]);                               \
+  XOR_LANE(d[4], x->S[I(i4, 4)], c[i4]);                               \
                                                                        \
   /* Then rho. */                                                      \
-  ROTL_LANE(b[0], b[0], ROT_##i0##_0);                                 \
-  ROTL_LANE(b[1], b[1], ROT_##i1##_1);                                 \
-  ROTL_LANE(b[2], b[2], ROT_##i2##_2);                                 \
-  ROTL_LANE(b[3], b[3], ROT_##i3##_3);                                 \
-  ROTL_LANE(b[4], b[4], ROT_##i4##_4);                                 \
+  ROTL_LANE(d[0], d[0], ROT_##i0##_0);                                 \
+  ROTL_LANE(d[1], d[1], ROT_##i1##_1);                                 \
+  ROTL_LANE(d[2], d[2], ROT_##i2##_2);                                 \
+  ROTL_LANE(d[3], d[3], ROT_##i3##_3);                                 \
+  ROTL_LANE(d[4], d[4], ROT_##i4##_4);                                 \
 } while (0)
 
   /* The basic chi operation is: z = w ^ (~a&b), but this involves an
@@ -435,55 +435,55 @@ static void keccak1600_round(keccak1600_state *z,
    * This is hairy because we must worry about complementation.
    */
   THETA_RHO(0, 1, 2, 3, 4);
-  CHI_COMPL(t, b[2]);                        /*         [.]               */
-  CHI_101_0(z->S[I(0, 0)], b[0], b[1], b[2]); /*  *   .   *          ->  . */
-  CHI_001_1(z->S[I(1, 0)], b[1], t,    b[3]); /*      .  [.]  *      ->  * */
-  CHI_110_1(z->S[I(2, 0)], b[2], b[3], b[4]); /*          *   *   .  ->  * */
-  CHI_101_0(z->S[I(3, 0)], b[3], b[4], b[0]); /*  *           *   .  ->  . */
-  CHI_010_0(z->S[I(4, 0)], b[4], b[0], b[1]); /*  *   .           .  ->  . */
+  CHI_COMPL(t, d[2]);                        /*         [.]               */
+  CHI_101_0(z->S[I(0, 0)], d[0], d[1], d[2]); /*  *   .   *          ->  . */
+  CHI_001_1(z->S[I(1, 0)], d[1], t,    d[3]); /*      .  [.]  *      ->  * */
+  CHI_110_1(z->S[I(2, 0)], d[2], d[3], d[4]); /*          *   *   .  ->  * */
+  CHI_101_0(z->S[I(3, 0)], d[3], d[4], d[0]); /*  *           *   .  ->  . */
+  CHI_010_0(z->S[I(4, 0)], d[4], d[0], d[1]); /*  *   .           .  ->  . */
 
   /* We'd better do iota before we forget. */
   XOR_LANE(z->S[I(0, 0)], z->S[I(0, 0)], rcon[i]);
 
   /* That was fun.  Maybe y' = 1 will be as good. */
   THETA_RHO(3, 4, 0, 1, 2);
-  CHI_COMPL(t, b[4]);                        /*                 [*]       */
-  CHI_101_0(z->S[I(0, 1)], b[0], b[1], b[2]); /*  *   .   *          ->  . */
-  CHI_010_0(z->S[I(1, 1)], b[1], b[2], b[3]); /*      .   *   .      ->  . */
-  CHI_101_0(z->S[I(2, 1)], b[2], b[3], t);    /*          *   .  [*] ->  . */
-  CHI_001_1(z->S[I(3, 1)], b[3], b[4], b[0]); /*  *           .   .  ->  * */
-  CHI_010_0(z->S[I(4, 1)], b[4], b[0], b[1]); /*  *   .           .  ->  . */
+  CHI_COMPL(t, d[4]);                        /*                 [*]       */
+  CHI_101_0(z->S[I(0, 1)], d[0], d[1], d[2]); /*  *   .   *          ->  . */
+  CHI_010_0(z->S[I(1, 1)], d[1], d[2], d[3]); /*      .   *   .      ->  . */
+  CHI_101_0(z->S[I(2, 1)], d[2], d[3], t);    /*          *   .  [*] ->  . */
+  CHI_001_1(z->S[I(3, 1)], d[3], d[4], d[0]); /*  *           .   .  ->  * */
+  CHI_010_0(z->S[I(4, 1)], d[4], d[0], d[1]); /*  *   .           .  ->  . */
 
   /* We're getting the hang of this.  The y' = 2 plane shouldn't be any
    * trouble.
    */
   THETA_RHO(1, 2, 3, 4, 0);
-  CHI_COMPL(t, b[3]);                        /*             [*]           */
-  CHI_101_0(z->S[I(0, 2)], b[0], b[1], b[2]); /*  *   .   *          ->  . */
-  CHI_010_0(z->S[I(1, 2)], b[1], b[2], b[3]); /*      .   *   .      ->  . */
-  CHI_110_1(z->S[I(2, 2)], b[2], t,    b[4]); /*          *  [*]  .  ->  * */
-  CHI_101_0(z->S[I(3, 2)], t,    b[4], b[0]); /*  *          [*]  .  ->  . */
-  CHI_010_0(z->S[I(4, 2)], b[4], b[0], b[1]); /*  *   .           .  ->  . */
+  CHI_COMPL(t, d[3]);                        /*             [*]           */
+  CHI_101_0(z->S[I(0, 2)], d[0], d[1], d[2]); /*  *   .   *          ->  . */
+  CHI_010_0(z->S[I(1, 2)], d[1], d[2], d[3]); /*      .   *   .      ->  . */
+  CHI_110_1(z->S[I(2, 2)], d[2], t,    d[4]); /*          *  [*]  .  ->  * */
+  CHI_101_0(z->S[I(3, 2)], t,    d[4], d[0]); /*  *          [*]  .  ->  . */
+  CHI_010_0(z->S[I(4, 2)], d[4], d[0], d[1]); /*  *   .           .  ->  . */
 
   /* This isn't as interesting any more.  Let's do y' = 3 before boredom sets
    * in.
    */
   THETA_RHO(4, 0, 1, 2, 3);
-  CHI_COMPL(t, b[3]);                        /*             [.]           */
-  CHI_010_0(z->S[I(0, 3)], b[0], b[1], b[2]); /*  .   *   .          ->  . */
-  CHI_101_0(z->S[I(1, 3)], b[1], b[2], b[3]); /*      *   .   *      ->  . */
-  CHI_001_1(z->S[I(2, 3)], b[2], t,    b[4]); /*          .  [.]  *  ->  * */
-  CHI_010_0(z->S[I(3, 3)], t,    b[4], b[0]); /*  .          [.]  *  ->  . */
-  CHI_101_0(z->S[I(4, 3)], b[4], b[0], b[1]); /*  .   *           *  ->  . */
+  CHI_COMPL(t, d[3]);                        /*             [.]           */
+  CHI_010_0(z->S[I(0, 3)], d[0], d[1], d[2]); /*  .   *   .          ->  . */
+  CHI_101_0(z->S[I(1, 3)], d[1], d[2], d[3]); /*      *   .   *      ->  . */
+  CHI_001_1(z->S[I(2, 3)], d[2], t,    d[4]); /*          .  [.]  *  ->  * */
+  CHI_010_0(z->S[I(3, 3)], t,    d[4], d[0]); /*  .          [.]  *  ->  . */
+  CHI_101_0(z->S[I(4, 3)], d[4], d[0], d[1]); /*  .   *           *  ->  . */
 
   /* Last plane.  Just y' = 4 to go. */
   THETA_RHO(2, 3, 4, 0, 1);
-  CHI_COMPL(t, b[1]);                        /*     [*]                   */
-  CHI_110_1(z->S[I(0, 4)], b[0], t,    b[2]); /*  *  [*]  .          ->  * */
-  CHI_101_0(z->S[I(1, 4)], t,    b[2], b[3]); /*     [*]  .   *      ->  . */
-  CHI_010_0(z->S[I(2, 4)], b[2], b[3], b[4]); /*          .   *   .  ->  . */
-  CHI_101_0(z->S[I(3, 4)], b[3], b[4], b[0]); /*  *           *   .  ->  . */
-  CHI_010_0(z->S[I(4, 4)], b[4], b[0], b[1]); /*  *   .           .  ->  . */
+  CHI_COMPL(t, d[1]);                        /*     [*]                   */
+  CHI_110_1(z->S[I(0, 4)], d[0], t,    d[2]); /*  *  [*]  .          ->  * */
+  CHI_101_0(z->S[I(1, 4)], t,    d[2], d[3]); /*     [*]  .   *      ->  . */
+  CHI_010_0(z->S[I(2, 4)], d[2], d[3], d[4]); /*          .   *   .  ->  . */
+  CHI_101_0(z->S[I(3, 4)], d[3], d[4], d[0]); /*  *           *   .  ->  . */
+  CHI_010_0(z->S[I(4, 4)], d[4], d[0], d[1]); /*  *   .           .  ->  . */
 
   /* And we're done. */
 #undef THETA_RHO
diff --git a/symm/latinpoly-def.h b/symm/latinpoly-def.h
new file mode 100644 (file)
index 0000000..af917fa
--- /dev/null
@@ -0,0 +1,469 @@
+/* -*-c-*-
+ *
+ * AEAD schemes based on Salsa20/ChaCha and Poly1305
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_LATINPOLY_DEF_H
+#define CATACOMB_LATINPOLY_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_CT_H
+#  include "ct.h"
+#endif
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+#  include "keysz.h"
+#endif
+
+#ifndef CATACOMB_LATINPOLY_H
+#  include "latinpoly.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+#ifndef CATACOMB_POLY1305_H
+#  include "poly1305.h"
+#endif
+
+#ifndef CATACOMB_SALSA20_H
+#  include "salsa20.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct latinpoly_aad {
+  gaead_aad a;
+  poly1305_ctx poly;
+} latinpoly_aad;
+
+typedef struct latinpoly_key {
+  gaead_key k;
+  octet key[SALSA20_KEYSZ];
+  size_t ksz;
+} latinpoly_key;
+
+/*----- Common definitions ------------------------------------------------*/
+
+/* Tables. */
+extern const octet latinpoly_noncesz[], latinpoly_tagsz[];
+
+/* AAD methods. */
+extern void latinpoly_aadhash_poly1305(gaead_aad */*a*/,
+                                      const void */*h*/, size_t /*hsz*/);
+extern void latinpoly_aadhash_naclbox(gaead_aad */*a*/,
+                                     const void */*h*/, size_t /*hsz*/);
+extern void latinpoly_aaddestroy(gaead_aad */*a*/);
+
+/* Variants. */
+enum { LPVAR_NACLBOX, LPVAR_POLY1305 };
+
+/* --- @latinpoly_tag@ --- *
+ *
+ * Arguments:  @const poly1305_ctx *aad@ = Poly1305 context hashing AAD
+ *             @poly1305_ctx *ct@ = Poly1305 context hashing ciphertext
+ *             @void *tag@ = where to write the tag
+ *
+ * Returns:    ---
+ *
+ * Use:                Completes a Latin-dance-Poly1305 tag, combining the AAD and
+ *             ciphertext hashes, appending their lengths, and writing the
+ *             final masked hash to @tag@.  The @ct@ context is clobbered.
+ */
+
+extern void latinpoly_tag(const poly1305_ctx */*aad*/,
+                         poly1305_ctx */*ct*/, void */*tag*/);
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define LATINPOLY_DEF(latin, base, name)                               \
+                                                                       \
+/* Utilities. */                                                       \
+                                                                       \
+/* Reinitialize the stream cipher and hash state given a new nonce. */ \
+static int reinit_##latin(x##latin##_ctx *ctx, int var,                \
+                         poly1305_ctx *aadpoly, poly1305_ctx *ctpoly,  \
+                         const void *n, size_t nsz)                    \
+{                                                                      \
+  poly1305_key pk;                                                     \
+  octet b[POLY1305_KEYSZ + POLY1305_MASKSZ];                           \
+                                                                       \
+  switch (nsz) {                                                       \
+    case SALSA20_NONCESZ:                                              \
+      memcpy(ctx->s.a, ctx->k, sizeof(ctx->k));                                \
+      base##_setnonce(&ctx->s, n);                                     \
+      break;                                                           \
+    case SALSA20_IETF_NONCESZ:                                         \
+      memcpy(ctx->s.a, ctx->k, sizeof(ctx->k));                                \
+      base##_setnonce_ietf(&ctx->s, n);                                        \
+      break;                                                           \
+    case XSALSA20_NONCESZ:                                             \
+      x##latin##_setnonce(ctx, n);                                     \
+      break;                                                           \
+    default:                                                           \
+      return (-1);                                                     \
+  }                                                                    \
+                                                                       \
+  latin##_encrypt(&ctx->s, 0, b, sizeof(b));                           \
+  poly1305_keyinit(&pk, b, POLY1305_KEYSZ);                            \
+  poly1305_macinit(ctpoly, &pk, b + POLY1305_KEYSZ);                   \
+  switch (var) {                                                       \
+    case LPVAR_NACLBOX:                                                        \
+      aadpoly->count = 0; aadpoly->nbuf = 0;                           \
+      break;                                                           \
+    case LPVAR_POLY1305:                                               \
+      poly1305_macinit(aadpoly, &pk, b + POLY1305_KEYSZ);              \
+      latin##_encrypt(&ctx->s, 0, 0, SALSA20_OUTSZ - sizeof(b));       \
+      break;                                                           \
+    default:                                                           \
+      assert(0);                                                       \
+  }                                                                    \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* AAD operations. */                                                  \
+                                                                       \
+static const gaead_aadops gaops_##latin##_poly1305 =                   \
+  { &latin##_poly1305, 0, latinpoly_aadhash_poly1305, latinpoly_aaddestroy }; \
+                                                                       \
+static const gaead_aadops gaops_##latin##_naclbox =                    \
+  { &latin##_naclbox, 0, latinpoly_aadhash_naclbox, latinpoly_aaddestroy }; \
+                                                                       \
+/* Encryption operations. */                                           \
+                                                                       \
+typedef struct gectx_##latin {                                         \
+  gaead_enc e;                                                         \
+  latinpoly_aad aad;                                                   \
+  x##latin##_ctx ctx;                                                  \
+  poly1305_ctx poly;                                                   \
+} gectx_##latin;                                                       \
+                                                                       \
+static gaead_aad *geaad_##latin(gaead_enc *e)                          \
+  { gectx_##latin *enc = (gectx_##latin *)e; return (&enc->aad.a); }   \
+                                                                       \
+static int gereinit_##latin##_poly1305(gaead_enc *e,                   \
+                                      const void *n, size_t nsz,       \
+                                      size_t hsz, size_t msz, size_t tsz) \
+{                                                                      \
+  gectx_##latin *enc = (gectx_##latin *)e;                             \
+  return (reinit_##latin(&enc->ctx, LPVAR_POLY1305,                    \
+                        &enc->aad.poly, &enc->poly, n, nsz));          \
+}                                                                      \
+                                                                       \
+static int gereinit_##latin##_naclbox(gaead_enc *e,                    \
+                                     const void *n, size_t nsz,        \
+                                     size_t hsz, size_t msz, size_t tsz) \
+{                                                                      \
+  gectx_##latin *enc = (gectx_##latin *)e;                             \
+  return (reinit_##latin(&enc->ctx, LPVAR_NACLBOX,                     \
+                        &enc->aad.poly, &enc->poly, n, nsz));          \
+}                                                                      \
+                                                                       \
+static int geenc_##latin(gaead_enc *e,                                 \
+                        const void *m, size_t msz, buf *b)             \
+{                                                                      \
+  gectx_##latin *enc = (gectx_##latin *)e;                             \
+  void *q;                                                             \
+                                                                       \
+  if (msz) { q = buf_get(b, msz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+  latin##_encrypt(&enc->ctx.s, m, q, msz);                             \
+  poly1305_hash(&enc->poly, q, msz);                                   \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int gedone_##latin##_common(gectx_##latin *enc,                 \
+                                  const latinpoly_aad *aad,            \
+                                  buf *b, size_t tsz)                  \
+{                                                                      \
+  if (tsz != POLY1305_TAGSZ) return (-1);                              \
+  assert((!enc->aad.poly.count && !enc->aad.poly.nbuf && !aad) ||      \
+        aad == &enc->aad);                                             \
+  if (!BOK(b)) return (-1);                                            \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int gedone_##latin##_poly1305(gaead_enc *e, const gaead_aad *a, \
+                                    buf *b, void *t, size_t tsz)       \
+{                                                                      \
+  gectx_##latin *enc = (gectx_##latin *)e;                             \
+  const latinpoly_aad *aad = (const latinpoly_aad *)a;                 \
+                                                                       \
+  if (gedone_##latin##_common(enc, aad, b, tsz)) return (-1);          \
+  latinpoly_tag(aad ? &aad->poly : 0, &enc->poly, t);                  \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int gedone_##latin##_naclbox(gaead_enc *e, const gaead_aad *a,  \
+                                   buf *b, void *t, size_t tsz)        \
+{                                                                      \
+  gectx_##latin *enc = (gectx_##latin *)e;                             \
+  const latinpoly_aad *aad = (const latinpoly_aad *)a;                 \
+                                                                       \
+  if (gedone_##latin##_common(enc, aad, b, tsz)) return (-1);          \
+  poly1305_done(&enc->poly, t);                                                \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static void gedestroy_##latin(gaead_enc *e)                            \
+  { gectx_##latin *enc = (gectx_##latin *)e; BURN(*enc); S_DESTROY(enc); } \
+                                                                       \
+static gaead_encops geops_##latin##_poly1305 =                         \
+  { &latin##_poly1305, geaad_##latin, gereinit_##latin##_poly1305,     \
+    geenc_##latin, gedone_##latin##_poly1305, gedestroy_##latin };     \
+                                                                       \
+static gaead_encops geops_##latin##_naclbox =                          \
+  { &latin##_naclbox, geaad_##latin, gereinit_##latin##_naclbox,       \
+    geenc_##latin, gedone_##latin##_naclbox, gedestroy_##latin };      \
+                                                                       \
+/* Decryption operations. */                                           \
+                                                                       \
+typedef struct gdctx_##latin {                                         \
+  gaead_dec d;                                                         \
+  latinpoly_aad aad;                                                   \
+  x##latin##_ctx ctx;                                                  \
+  poly1305_ctx poly;                                                   \
+} gdctx_##latin;                                                       \
+                                                                       \
+static gaead_aad *gdaad_##latin(gaead_dec *d)                          \
+  { gdctx_##latin *dec = (gdctx_##latin *)d; return (&dec->aad.a); }   \
+                                                                       \
+static int gdreinit_##latin##_poly1305(gaead_dec *d,                   \
+                                      const void *n, size_t nsz,       \
+                                      size_t hsz, size_t msz, size_t tsz) \
+{                                                                      \
+  gdctx_##latin *dec = (gdctx_##latin *)d;                             \
+  return (reinit_##latin(&dec->ctx, LPVAR_POLY1305,                    \
+                        &dec->aad.poly, &dec->poly, n, nsz));          \
+}                                                                      \
+                                                                       \
+static int gdreinit_##latin##_naclbox(gaead_dec *d,                    \
+                                     const void *n, size_t nsz,        \
+                                     size_t hsz, size_t msz, size_t tsz) \
+{                                                                      \
+  gdctx_##latin *dec = (gdctx_##latin *)d;                             \
+  return (reinit_##latin(&dec->ctx, LPVAR_NACLBOX,                     \
+                        &dec->aad.poly, &dec->poly, n, nsz));          \
+}                                                                      \
+                                                                       \
+static int gddec_##latin(gaead_dec *d,                                 \
+                        const void *c, size_t csz, buf *b)             \
+{                                                                      \
+  gdctx_##latin *dec = (gdctx_##latin *)d;                             \
+  void *q;                                                             \
+                                                                       \
+  if (csz) { q = buf_get(b, csz); if (!q) return (-1); }               \
+  else q = 0;                                                          \
+  poly1305_hash(&dec->poly, c, csz);                                   \
+  latin##_encrypt(&dec->ctx.s, c, q, csz);                             \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int gddone_##latin##_common(gdctx_##latin *dec,                 \
+                                  const latinpoly_aad *aad,            \
+                                  buf *b, size_t tsz)                  \
+{                                                                      \
+  if (tsz != POLY1305_TAGSZ) return (-1);                              \
+  assert((!dec->aad.poly.count && !dec->aad.poly.nbuf && !aad) ||      \
+        aad == &dec->aad);                                             \
+  if (!BOK(b)) return (-1);                                            \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+static int gddone_##latin##_poly1305(gaead_dec *d, const gaead_aad *a, \
+                                    buf *b, const void *t, size_t tsz) \
+{                                                                      \
+  gdctx_##latin *dec = (gdctx_##latin *)d;                             \
+  const latinpoly_aad *aad = (const latinpoly_aad *)a;                 \
+  octet u[POLY1305_TAGSZ];                                             \
+                                                                       \
+  if (gddone_##latin##_common(dec, aad, b, tsz)) return (-1);          \
+  latinpoly_tag(aad ? &aad->poly : 0, &dec->poly, u);                  \
+  if (ct_memeq(t, u, POLY1305_TAGSZ)) return (+1);                     \
+  else return (0);                                                     \
+}                                                                      \
+                                                                       \
+static int gddone_##latin##_naclbox(gaead_dec *d, const gaead_aad *a,  \
+                                   buf *b, const void *t, size_t tsz)  \
+{                                                                      \
+  gdctx_##latin *dec = (gdctx_##latin *)d;                             \
+  const latinpoly_aad *aad = (const latinpoly_aad *)a;                 \
+  octet u[POLY1305_TAGSZ];                                             \
+                                                                       \
+  if (gddone_##latin##_common(dec, aad, b, tsz)) return (-1);          \
+  poly1305_done(&dec->poly, u);                                                \
+  if (ct_memeq(t, u, POLY1305_TAGSZ)) return (+1);                     \
+  else return (0);                                                     \
+}                                                                      \
+                                                                       \
+static void gddestroy_##latin(gaead_dec *d)                            \
+  { gdctx_##latin *dec = (gdctx_##latin *)d; BURN(*dec); S_DESTROY(dec); } \
+                                                                       \
+static gaead_decops gdops_##latin##_poly1305 =                         \
+  { &latin##_poly1305, gdaad_##latin, gdreinit_##latin##_poly1305,     \
+    gddec_##latin, gddone_##latin##_poly1305, gddestroy_##latin };     \
+                                                                       \
+static gaead_decops gdops_##latin##_naclbox =                          \
+  { &latin##_poly1305, gdaad_##latin, gdreinit_##latin##_naclbox,      \
+    gddec_##latin, gddone_##latin##_naclbox, gddestroy_##latin };      \
+                                                                       \
+/* Key operations. */                                                  \
+                                                                       \
+static gaead_enc *gkenc_##latin##_poly1305(const gaead_key *k,         \
+                                          const void *n, size_t nsz,   \
+                                          size_t hsz, size_t msz,      \
+                                          size_t tsz)                  \
+{                                                                      \
+  latinpoly_key *key = (latinpoly_key *)k;                             \
+  gectx_##latin *enc = S_CREATE(gectx_##latin);                                \
+                                                                       \
+  enc->e.ops = &geops_##latin##_poly1305;                              \
+  enc->aad.a.ops = &gaops_##latin##_poly1305;                          \
+  x##latin##_init(&enc->ctx, key->key, key->ksz, 0);                   \
+  if (reinit_##latin(&enc->ctx, LPVAR_POLY1305,                                \
+                    &enc->aad.poly, &enc->poly, n, nsz))               \
+    { gedestroy_##latin(&enc->e); return (0); }                                \
+  return (&enc->e);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_enc *gkenc_##latin##_naclbox(const gaead_key *k,          \
+                                         const void *n, size_t nsz,    \
+                                         size_t hsz, size_t msz,       \
+                                         size_t tsz)                   \
+{                                                                      \
+  latinpoly_key *key = (latinpoly_key *)k;                             \
+  gectx_##latin *enc = S_CREATE(gectx_##latin);                                \
+                                                                       \
+  enc->e.ops = &geops_##latin##_naclbox;                               \
+  enc->aad.a.ops = &gaops_##latin##_naclbox;                           \
+  x##latin##_init(&enc->ctx, key->key, key->ksz, 0);                   \
+  if (reinit_##latin(&enc->ctx, LPVAR_NACLBOX,                         \
+                    &enc->aad.poly, &enc->poly, n, nsz))               \
+    { gedestroy_##latin(&enc->e); return (0); }                                \
+  return (&enc->e);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_dec *gkdec_##latin##_poly1305(const gaead_key *k,         \
+                                          const void *n, size_t nsz,   \
+                                          size_t hsz, size_t msz,      \
+                                          size_t tsz)                  \
+{                                                                      \
+  latinpoly_key *key = (latinpoly_key *)k;                             \
+  gdctx_##latin *dec = S_CREATE(gdctx_##latin);                                \
+                                                                       \
+  dec->d.ops = &gdops_##latin##_poly1305;                              \
+  dec->aad.a.ops = &gaops_##latin##_poly1305;                          \
+  x##latin##_init(&dec->ctx, key->key, key->ksz, 0);                   \
+  if (reinit_##latin(&dec->ctx, LPVAR_POLY1305,                                \
+                    &dec->aad.poly, &dec->poly, n, nsz))               \
+    { gddestroy_##latin(&dec->d); return (0); }                                \
+  return (&dec->d);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_dec *gkdec_##latin##_naclbox(const gaead_key *k,          \
+                                         const void *n, size_t nsz,    \
+                                         size_t hsz, size_t msz,       \
+                                         size_t tsz)                   \
+{                                                                      \
+  latinpoly_key *key = (latinpoly_key *)k;                             \
+  gdctx_##latin *dec = S_CREATE(gdctx_##latin);                                \
+                                                                       \
+  dec->d.ops = &gdops_##latin##_naclbox;                               \
+  dec->aad.a.ops = &gaops_##latin##_naclbox;                           \
+  x##latin##_init(&dec->ctx, key->key, key->ksz, 0);                   \
+  if (reinit_##latin(&dec->ctx, LPVAR_NACLBOX,                         \
+                    &dec->aad.poly, &dec->poly, n, nsz))               \
+    { gddestroy_##latin(&dec->d); return (0); }                                \
+  return (&dec->d);                                                    \
+}                                                                      \
+                                                                       \
+static void gkdestroy_##latin(gaead_key *k)                            \
+  { latinpoly_key *key = (latinpoly_key *)k; BURN(*key); S_DESTROY(key); } \
+                                                                       \
+static const gaead_keyops gkops_##latin##_poly1305 =                   \
+  { &latin##_poly1305, 0,                                              \
+    gkenc_##latin##_poly1305, gkdec_##latin##_poly1305,                        \
+    gkdestroy_##latin };                                               \
+                                                                       \
+static const gaead_keyops gkops_##latin##_naclbox =                    \
+  { &latin##_naclbox, 0,                                               \
+    gkenc_##latin##_naclbox, gkdec_##latin##_naclbox,                  \
+    gkdestroy_##latin };                                               \
+                                                                       \
+/* Class definition. */                                                        \
+                                                                       \
+static gaead_key *gkey_##latin##_common(const gaead_keyops *ops,       \
+                                       const void *k, size_t ksz)      \
+{                                                                      \
+  latinpoly_key *key = S_CREATE(latinpoly_key);                                \
+                                                                       \
+  key->k.ops = ops;                                                    \
+  KSZ_ASSERT(latin, ksz); memcpy(key->key, k, ksz); key->ksz = ksz;    \
+  return (&key->k);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_key *gkey_##latin##_poly1305(const void *k, size_t ksz)   \
+  { return (gkey_##latin##_common(&gkops_##latin##_poly1305, k, ksz)); } \
+                                                                       \
+static gaead_key *gkey_##latin##_naclbox(const void *k, size_t ksz)    \
+  { return (gkey_##latin##_common(&gkops_##latin##_naclbox, k, ksz)); }        \
+                                                                       \
+const gcaead latin##_poly1305 = {                                      \
+  name "-poly1305", latin##_keysz, latinpoly_noncesz, latinpoly_tagsz, \
+  64, 0, 0, AEADF_AADNDEP,                                             \
+  gkey_##latin##_poly1305                                              \
+};                                                                     \
+                                                                       \
+const gcaead latin##_naclbox = {                                       \
+  name "-naclbox", latin##_keysz, latinpoly_noncesz, latinpoly_tagsz,  \
+  64, 0, 0, AEADF_AADNDEP | AEADF_NOAAD,                               \
+  gkey_##latin##_naclbox                                               \
+};
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/latinpoly-test.c b/symm/latinpoly-test.c
new file mode 100644 (file)
index 0000000..5a914e5
--- /dev/null
@@ -0,0 +1,116 @@
+/* -*-c-*-
+ *
+ * Testing for AEAD schemes based on Salsa20/ChaCha and Poly1305
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "latinpoly-def.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @latinpoly_test@ --- *
+ *
+ * Arguments:  @gcaead *aec@ = authenticated encryption class to test
+ *             @dstr *v@ = pointer to test-vector
+ *
+ * Returns:    Nonzero if the test passed, zero on failure.
+ */
+
+int latinpoly_test(const gcaead *aec, dstr *v)
+{
+  gaead_key *k;
+  gaead_aad *a;
+  gaead_enc *e; gaead_dec *d;
+  dstr out = DSTR_INIT, tag = DSTR_INIT;
+  buf b;
+  int rc;
+  int ok = 1;
+
+  k = GAEAD_KEY(aec, v[0].buf, v[0].len);
+
+  dstr_reset(&out); dstr_ensure(&out, v[3].len);
+  dstr_reset(&tag); dstr_ensure(&tag, POLY1305_TAGSZ);
+  e = GAEAD_ENC(k, v[1].buf, v[1].len, 0, 0, 0);
+  a = GAEAD_AAD(e); GAEAD_HASH(a, v[2].buf, v[2].len);
+  buf_init(&b, out.buf, out.sz);
+  rc = GAEAD_ENCRYPT(e, v[3].buf, v[3].len, &b);
+  if (rc) { printf("!! encrypt reports failure\n"); goto encfail; }
+  rc = GAEAD_DONE(e, a, &b, tag.buf, POLY1305_TAGSZ);
+  if (rc) { printf("!! encryptdone reports failure\n"); goto encfail; }
+
+  out.len = BLEN(&b); tag.len = POLY1305_TAGSZ;
+  if (out.len != v[4].len || memcmp(out.buf, v[4].buf, v[4].len) ||
+      memcmp(tag.buf, v[5].buf, v[5].len)) {
+  encfail:
+    ok = 0;
+    printf("\n%s encrypt FAILED", aec->name);
+    printf("\n     key = "); type_hex.dump(&v[0], stdout);
+    printf("\n   nonce = "); type_hex.dump(&v[1], stdout);
+    printf("\n  header = "); type_hex.dump(&v[2], stdout);
+    printf("\n message = "); type_hex.dump(&v[3], stdout);
+    printf("\n  exp ct = "); type_hex.dump(&v[4], stdout);
+    printf("\n calc ct = "); type_hex.dump(&out, stdout);
+    printf("\n exp tag = "); type_hex.dump(&v[5], stdout);
+    printf("\ncalc tag = "); type_hex.dump(&tag, stdout);
+    putchar('\n');
+  }
+  GAEAD_DESTROY(a);
+  GAEAD_DESTROY(e);
+
+  dstr_reset(&out); dstr_ensure(&out, v[3].len);
+  dstr_reset(&tag); dstr_ensure(&tag, POLY1305_TAGSZ);
+  d = GAEAD_DEC(k, v[1].buf, v[1].len, 0, 0, 0);
+  a = GAEAD_AAD(d); GAEAD_HASH(a, v[2].buf, v[2].len);
+  buf_init(&b, out.buf, out.sz);
+  rc = GAEAD_DECRYPT(d, v[4].buf, v[4].len, &b);
+  if (rc) { printf("!! decrypt reports failure\n"); goto decfail; }
+  rc = GAEAD_DONE(e, a, &b, v[5].buf, POLY1305_TAGSZ);
+  if (rc < 0) { printf("!! decryptdone reports failure\n"); goto decfail; }
+
+  out.len = BLEN(&b); tag.len = POLY1305_TAGSZ;
+  if (out.len != v[3].len || memcmp(out.buf, v[3].buf, v[3].len) || !rc) {
+  decfail:
+    ok = 0;
+    printf("\ndecrypt FAILED");
+    printf("\n     key = "); type_hex.dump(&v[0], stdout);
+    printf("\n   nonce = "); type_hex.dump(&v[1], stdout);
+    printf("\n  header = "); type_hex.dump(&v[2], stdout);
+    printf("\n  cipher = "); type_hex.dump(&v[4], stdout);
+    printf("\n exp msg = "); type_hex.dump(&v[3], stdout);
+    printf("\ncalc msg = "); type_hex.dump(&out, stdout);
+    printf("\n     tag = "); type_hex.dump(&v[5], stdout);
+    printf("\n  verify %s", rc > 0 ? "ok" : "FAILED");
+    putchar('\n');
+  }
+  GAEAD_DESTROY(a);
+  GAEAD_DESTROY(d);
+
+  GAEAD_DESTROY(k);
+  dstr_destroy(&out); dstr_destroy(&tag);
+  return (ok);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/symm/latinpoly-test.h b/symm/latinpoly-test.h
new file mode 100644 (file)
index 0000000..2cafef3
--- /dev/null
@@ -0,0 +1,65 @@
+/* -*-c-*-
+ *
+ * Testing for AEAD schemes based on Salsa20/ChaCha and Poly1305
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_LATINPOLY_TEST_H
+#define CATACOMB_LATINPOLY_TEST_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/dstr.h>
+#include <mLib/testrig.h>
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @latinpoly_test@ --- *
+ *
+ * Arguments:  @gcaead *aec@ = authenticated encryption class to test
+ *             @dstr *v@ = pointer to test-vector
+ *
+ * Returns:    Nonzero if the test passed, zero on failure.
+ *
+ * Use:                Checks a test vector.  This internal function is not
+ *             available outside of Catacomb's build tree.
+ */
+
+extern int latinpoly_test(const gcaead */*aec*/, dstr */*v*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/latinpoly.c b/symm/latinpoly.c
new file mode 100644 (file)
index 0000000..29ba71a
--- /dev/null
@@ -0,0 +1,97 @@
+/* -*-c-*-
+ *
+ * AEAD schemes based on Salsa20/ChaCha and Poly1305
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+
+#include "gaead.h"
+#include "keysz.h"
+#include "latinpoly-def.h"
+
+#include "poly1305.h"
+#include "salsa20.h"
+
+/*----- Common definitions ------------------------------------------------*/
+
+const octet
+  latinpoly_noncesz[] = { KSZ_SET, SALSA20_NONCESZ, SALSA20_IETF_NONCESZ,
+                         XSALSA20_NONCESZ, 0 },
+  latinpoly_tagsz[] = { KSZ_SET, POLY1305_TAGSZ, 0 };
+
+/* AAD handling. */
+
+void latinpoly_aadhash_poly1305(gaead_aad *a, const void *h, size_t hsz)
+{
+  latinpoly_aad *aad = (latinpoly_aad *)a;
+  poly1305_hash(&aad->poly, h, hsz);
+}
+
+void latinpoly_aadhash_naclbox(gaead_aad *a, const void *h, size_t hsz)
+  { assert(!hsz); }
+
+void latinpoly_aaddestroy(gaead_aad *a) { ; }
+
+/* --- @latinpoly_tag@ --- *
+ *
+ * Arguments:  @const poly1305_ctx *aad@ = Poly1305 context hashing AAD
+ *             @poly1305_ctx *ct@ = Poly1305 context hashing ciphertext
+ *             @void *tag@ = where to write the tag
+ *
+ * Returns:    ---
+ *
+ * Use:                Completes a Latin-dance-Poly1305 tag, combining the AAD and
+ *             ciphertext hashes, appending their lengths, and writing the
+ *             final masked hash to @tag@.  The @ct@ context is clobbered.
+ */
+
+/* Write the length of data pushed through Poly1305 as a 64-bit integer. */
+static void putlen(octet *p, const poly1305_ctx *poly)
+{
+  uint32 lo = U32((poly->count << 4) | poly->nbuf),
+    hi = U32(poly->count >> 28);
+  STORE32_L(p + 0, lo); STORE32_L(p + 4, hi);
+}
+
+void latinpoly_tag(const poly1305_ctx *aad, poly1305_ctx *ct, void *tag)
+{
+  octet b[16];
+  poly1305_ctx t;
+
+  putlen(b + 8, ct); poly1305_flushzero(ct);
+  if (!aad) memset(b, 0, 8);
+  else {
+    putlen(b + 0, aad);
+    t = *aad; poly1305_flushzero(&t); poly1305_concat(ct, &t, ct);
+  }
+  poly1305_hash(ct, b, 16); poly1305_done(ct, tag);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/symm/latinpoly.h b/symm/latinpoly.h
new file mode 100644 (file)
index 0000000..a9bb25e
--- /dev/null
@@ -0,0 +1,82 @@
+/* -*-c-*-
+ *
+ * AEAD schemes based on Salsa20/ChaCha and Poly1305
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Notes on this construction ----------------------------------------*
+ *
+ * The AEAD class @chacha20_poly1305@ with a 96-bit nonce is exactly the
+ * scheme specified in RFC7539.  This implementation extends that
+ * specification in two ways:
+ *
+ *   * It permits ciphers other than ChaCha20: specifically ChaCha%$r$% and
+ *     Salsa20/%$r$% with %$r \in \{ 8, 12, 20 \}$%.
+ *
+ *   * It allows nonces of 64, 96, and 192 bits.  A 64-bit nonce matches
+ *     Bernstein's original specification of Salsa20 and ChaCha; the 96-bit
+ *     nonce matches RFC7539; and the 192-bit nonce matches Bernstein's
+ *     XSalsa20.  The implementation uses XSalsa20 or XChaCha as appropriate
+ *     automatically based on the provided nonce length.
+ *
+ * These extensions do not significantly affect Procter's security analysis
+ * except that an application should not mix nonce sizes with the same key.
+ * (It is possible to do this safely, but it requires detailed understanding
+ * of how everything fits together and isn't worth the effort.)
+ *
+ * The @salsa20_naclbox@ with a 192-bit nonce is exactly the scheme
+ * implemented in Bernstein's `NaCl' library as @crypto_secretbox@, except
+ * that it's flexible regarding tag placement rather than insisting on
+ * prefixing it to the ciphertext.  Unlike NaCl, we provide a restartable
+ * interface, and allow the use of other ciphers and nonce lengths.
+ */
+
+#ifndef CATACOMB_LATINPOLY_H
+#define CATACOMB_LATINPOLY_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+/*----- Definitions -------------------------------------------------------*/
+
+extern const gcaead
+  chacha20_poly1305, chacha12_poly1305, chacha8_poly1305,
+  chacha20_naclbox, chacha12_naclbox, chacha8_naclbox,
+  salsa20_poly1305, salsa2012_poly1305, salsa208_poly1305,
+  salsa20_naclbox, salsa2012_naclbox, salsa208_naclbox;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index 832cd07..0b2df3d 100644 (file)
@@ -82,16 +82,10 @@ const octet pre##_mgfkeysz[] = { KSZ_ANY, PRE##_HASHSZ };           \
  */                                                                    \
                                                                        \
 void pre##_mgfkeybegin(pre##_mgfctx *k)                                        \
-{                                                                      \
-  k->c = 0;                                                            \
-  k->bsz = 0;                                                          \
-  pre##_init(&k->k);                                                   \
-}                                                                      \
+  { k->c = 0; k->off = 0; pre##_init(&k->k); }                         \
                                                                        \
 void pre##_mgfkeyadd(pre##_mgfctx *k, const void *p, size_t sz)                \
-{                                                                      \
-  pre##_hash(&k->k, p, sz);                                            \
-}                                                                      \
+  { pre##_hash(&k->k, p, sz); }                                                \
                                                                        \
 /* ---- @pre_mgfinit@ --- *                                            \
  *                                                                     \
@@ -106,12 +100,7 @@ void pre##_mgfkeyadd(pre##_mgfctx *k, const void *p, size_t sz)            \
  */                                                                    \
                                                                        \
 void pre##_mgfinit(pre##_mgfctx *k, const void *p, size_t sz)          \
-{                                                                      \
-  k->c = 0;                                                            \
-  k->bsz = 0;                                                          \
-  pre##_init(&k->k);                                                   \
-  pre##_hash(&k->k, p, sz);                                            \
-}                                                                      \
+  { k->c = 0; k->off = 0; pre##_init(&k->k); pre##_hash(&k->k, p, sz); } \
                                                                        \
 /* --- @pre_mgfencrypt@ --- *                                          \
  *                                                                     \
@@ -133,54 +122,35 @@ void pre##_mgfinit(pre##_mgfctx *k, const void *p, size_t sz)             \
 void pre##_mgfencrypt(pre##_mgfctx *k, const void *s,                  \
                      void *d, size_t sz)                               \
 {                                                                      \
+  pre##_ctx h;                                                         \
   const octet *ss = s;                                                 \
   octet *dd = d;                                                       \
+  const octet *p;                                                      \
+  size_t off;                                                          \
                                                                        \
   /* --- Empty the buffer if there's anything there --- */             \
                                                                        \
-  if (k->bsz) {                                                                \
-    const octet *p = k->buf + PRE##_HASHSZ - k->bsz;                   \
-    size_t n = sz > k->bsz ? k->bsz : sz;                              \
-    sz -= n;                                                           \
-    k->bsz -= n;                                                       \
-    if (dd) {                                                          \
-      if (!ss) {                                                       \
-       memcpy(dd, p, n);                                               \
-       dd += n;                                                        \
-      } else {                                                         \
-       while (n) {                                                     \
-         *dd++ = *ss++ ^ *p++;                                         \
-         n--;                                                          \
-       }                                                               \
-      }                                                                        \
-    }                                                                  \
+  if (k->off) {                                                                \
+    p = k->b + PRE##_HASHSZ - k->off;                                  \
+    off = sz > k->off ? k->off : sz;                                   \
+    sz -= off; k->off -= off;                                          \
+    if (!dd) /* do nothing */;                                         \
+    else if (!ss) { memcpy(dd, p, off); dd += off; }                   \
+    else while (off--) *dd++ = *ss++ ^ *p++;                           \
   }                                                                    \
                                                                        \
   /* --- While necessary, generate some more mask --- */               \
                                                                        \
   while (sz) {                                                         \
-    pre##_ctx c = k->k;                /* Not quick! */                        \
-    size_t n;                                                          \
-                                                                       \
-    STORE32(k->buf, k->c);                                             \
-    k->c++;                                                            \
-    pre##_hash(&c, k->buf, 4);                                         \
-    pre##_done(&c, k->buf);                                            \
-    n = sz > PRE##_HASHSZ ? PRE##_HASHSZ : sz;                         \
-    k->bsz = PRE##_HASHSZ - n;                                         \
-    sz -= n;                                                           \
-    if (dd) {                                                          \
-      const octet *p = k->buf;                                         \
-      if (!ss) {                                                       \
-       memcpy(dd, p, n);                                               \
-       dd += n;                                                        \
-      } else {                                                         \
-       while (n) {                                                     \
-         *dd++ = *ss++ ^ *p++;                                         \
-         n--;                                                          \
-       }                                                               \
-      }                                                                        \
-    }                                                                  \
+    STORE32(k->b, k->c); k->c++;                                       \
+    h = k->k; pre##_hash(&h, k->b, 4); pre##_done(&h, k->b);           \
+    off = sz > PRE##_HASHSZ ? PRE##_HASHSZ : sz;                       \
+    k->off = PRE##_HASHSZ - off;                                       \
+    sz -= off;                                                         \
+    p = k->b;                                                          \
+    if (!dd) /* do nothing */;                                         \
+    else if (!ss) { memcpy(dd, p, off); dd += off; }                   \
+    else while (off--) *dd++ = *ss++ ^ *p++;                           \
   }                                                                    \
 }                                                                      \
                                                                        \
@@ -196,10 +166,7 @@ void pre##_mgfencrypt(pre##_mgfctx *k, const void *s,                      \
  */                                                                    \
                                                                        \
 void pre##_mgfsetindex(pre##_mgfctx *k, uint32 c)                      \
-{                                                                      \
-  k->c = c;                                                            \
-  k->bsz = 0;                                                          \
-}                                                                      \
+  { k->c = c; k->off = 0; }                                            \
                                                                        \
 /* --- Generic cipher interface --- */                                 \
                                                                        \
@@ -219,17 +186,10 @@ static gcipher *ginit(const void *k, size_t sz)                           \
 }                                                                      \
                                                                        \
 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_mgfencrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_mgfencrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdestroy(gcipher *c)                                       \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  BURN(*g);                                                            \
-  S_DESTROY(g);                                                                \
-}                                                                      \
+  { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }                     \
                                                                        \
 static const gcipher_ops gops = {                                      \
   &pre##_mgf,                                                          \
@@ -320,10 +280,7 @@ static uint32 grword(grand *r)                                             \
 }                                                                      \
                                                                        \
 static void grfill(grand *r, void *p, size_t sz)                       \
-{                                                                      \
-  grctx *g = (grctx *)r;                                               \
-  pre##_mgfencrypt(&g->k, 0, p, sz);                                   \
-}                                                                      \
+  { grctx *g = (grctx *)r; pre##_mgfencrypt(&g->k, 0, p, sz); }                \
                                                                        \
 static const grand_ops grops = {                                       \
   name "-mgf",                                                         \
@@ -359,9 +316,7 @@ MGF_TESTX(PRE, pre, name, fname)
 
 #ifdef TEST_RIG
 
-#include <stdio.h>
-
-#include "daftstory.h"
+#include "modes-test.h"
 
 /* --- @MGF_TEST@ --- *
  *
@@ -372,81 +327,23 @@ MGF_TESTX(PRE, pre, name, fname)
 
 #define MGF_TESTX(PRE, pre, name, fname)                               \
                                                                        \
-/* --- Initial plaintext for the test --- */                           \
-                                                                       \
-static const octet text[] = TEXT;                                      \
+static pre##_mgfctx ctx;                                               \
                                                                        \
-/* --- Key and IV to use --- */                                                \
+static void pre##_mgf_test_setup(const octet *k, size_t ksz)           \
+  { pre##_mgfinit(&ctx, k, ksz); }                                     \
                                                                        \
-static const octet key[] = KEY;                                                \
+static void pre##_mgf_test_reset(const octet *iv)                      \
+  { pre##_mgfsetindex(&ctx, 0); }                                      \
                                                                        \
-/* --- Buffers for encryption and decryption output --- */             \
+static void pre##_mgf_test_enc(const octet *s, octet *d, size_t sz)    \
+  { pre##_mgfencrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-static octet ct[sizeof(text)];                                         \
-static octet pt[sizeof(text)];                                         \
-                                                                       \
-static void hexdump(const octet *p, size_t sz)                         \
+int main(int argc, char *argv[])                                       \
 {                                                                      \
-  const octet *q = p + sz;                                             \
-  for (sz = 0; p < q; p++, sz++) {                                     \
-    printf("%02x", *p);                                                        \
-    if ((sz + 1) % PRE##_HASHSZ == 0)                                  \
-      putchar(':');                                                    \
-  }                                                                    \
-}                                                                      \
-                                                                       \
-int main(void)                                                         \
-{                                                                      \
-  size_t sz = 0, rest;                                                 \
-  pre##_mgfctx ctx;                                                    \
-  int status = 0;                                                      \
-  int done = 0;                                                                \
-                                                                       \
-  size_t keysz = strlen((const char *)key);                            \
-                                                                       \
-  fputs(name "-mgf: ", stdout);                                                \
-                                                                       \
-  pre##_mgfinit(&ctx, key, keysz);                                     \
-                                                                       \
-  while (sz <= sizeof(text)) {                                         \
-    rest = sizeof(text) - sz;                                          \
-    memcpy(ct, text, sizeof(text));                                    \
-    pre##_mgfsetindex(&ctx, 0);                                                \
-    pre##_mgfencrypt(&ctx, ct, ct, sz);                                        \
-    pre##_mgfencrypt(&ctx, ct + sz, ct + sz, rest);                    \
-    memcpy(pt, ct, sizeof(text));                                      \
-    pre##_mgfsetindex(&ctx, 0);                                                \
-    pre##_mgfencrypt(&ctx, pt, pt, rest);                              \
-    pre##_mgfencrypt(&ctx, pt + rest, pt + rest, sz);                  \
-    if (memcmp(pt, text, sizeof(text)) == 0) {                         \
-      done++;                                                          \
-      if (sizeof(text) < 40 || done % 8 == 0)                          \
-       fputc('.', stdout);                                             \
-      if (done % 480 == 0)                                             \
-       fputs("\n\t", stdout);                                          \
-      fflush(stdout);                                                  \
-    } else {                                                           \
-      printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
-      status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz);                        \
-       printf(", "); hexdump(text + sz, rest);                         \
-       fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz);                  \
-       printf(", "); hexdump(ct + sz, rest);                           \
-       fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz);                  \
-       printf(", "); hexdump(pt + sz, rest);                           \
-       fputc('\n', stdout);                                            \
-      fputc('\n', stdout);                                             \
-    }                                                                  \
-    if (sz < 63)                                                       \
-      sz++;                                                            \
-    else                                                               \
-      sz += 9;                                                         \
-  }                                                                    \
-                                                                       \
-  fputs(status ? " failed\n" : " ok\n", stdout);                       \
-  return (status);                                                     \
+  return test_encmode(fname "-mgf", 0, PRE##_HASHSZ, 1, 0,             \
+                     pre##_mgf_test_setup, pre##_mgf_test_reset,       \
+                     pre##_mgf_test_enc, pre##_mgf_test_enc,           \
+                     argc, argv);                                      \
 }
 
 #else
index d5b0fd1..934f012 100644 (file)
@@ -61,8 +61,8 @@
 typedef struct pre##_mgfctx {                                          \
   pre##_ctx k;                         /* Underlying key context */    \
   uint32 c;                            /* Counter */                   \
-  octet buf[PRE##_HASHSZ];             /* Output buffer */             \
-  size_t bsz;                          /* Size of buffered data */     \
+  octet b[PRE##_HASHSZ];               /* Output buffer */             \
+  unsigned off;                                /* Size of buffered data */     \
 } pre##_mgfctx;                                                                \
                                                                        \
 /* --- Other useful constants --- */                                   \
diff --git a/symm/modes-test.c b/symm/modes-test.c
new file mode 100644 (file)
index 0000000..b06d230
--- /dev/null
@@ -0,0 +1,546 @@
+/* -*-c-*-
+ *
+ * Common code for testing encryption modes
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+
+#include <mLib/alloc.h>
+#include <mLib/bits.h>
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+#include "modes-test.h"
+
+/*----- The reference data ------------------------------------------------*/
+
+#ifdef SMALL_TEST
+static const octet text[] = "A small piece of text for testing encryption.";
+#else
+#define STORY "\
+Once upon a time there were a beautiful princess, a slightly nutty wizard,\n\
+and a watermelon.  Now, the watermelon had decided that it probably wasn't\n\
+going to get very far with the princess unless it did something pretty\n\
+drastic.  So it asked the wizard to turn it into a handsome prince.\n\
+\n\
+At least, this is the way that the wizard viewed the situation.  He might\n\
+have just hallucinated it all; those mushrooms had looked ever so nice.\n\
+\n\
+Back to the point.  The watermelon had expressed its desire not to be a\n\
+watermelon any more.  And the wizard was probably tripping something quite\n\
+powerful.  He hunted around a bit for his staff, and mumbled something\n\
+that film directors would think of as sounding appropriately arcane and\n\
+mystical (but was, in fact, just the ingredients list for an ancient\n\
+remedy for athlete's foot) and *pop*.  Cooked watermelon.  Yuk.\n\
+\n\
+Later in the year, the princess tripped over the hem of her dress, fell\n\
+down a spiral staircase, and died.  The king ordered dressmakers to attach\n\
+safety warnings to long dresses.\n\
+\n\
+And the wizard?         Who cares?\n\
+"
+static const octet text[] = STORY STORY;
+#endif
+
+#define TEXTSZ (sizeof(text))
+
+static const octet key[] = "Penguins rule OK, rhubarb cauliflower",
+  iv[] = "EdgewareCatacomb, parsley, sage, rosemary and thyme";
+
+/*----- Static variables --------------------------------------------------*/
+
+/* Encryption buffers, for ciphertext, recovered plaintext, and consistency
+ * reference.
+ */
+static octet ct[TEXTSZ], pt[TEXTSZ], ref[TEXTSZ];
+
+/* A resizeable buffer for verifying regression data. */
+static octet *t = 0; size_t tsz = 0;
+
+/*----- Diagnostic utilities ----------------------------------------------*/
+
+/* Print the @sz@-byte buffer @p@, beginning at offset @off@ within some
+ * larger buffer, marking block boundaries every @blksz@ bytes.
+ */
+static void hexdump(const octet *p, size_t sz, size_t off, size_t blksz)
+{
+  const octet *q = p + sz;
+  for (sz = 0; p < q; p++, sz++) {
+    printf("%02x", *p);
+    if ((off + sz + 1)%blksz == 0) putchar(':');
+  }
+}
+
+/* Print the buffer @p@, labelling it as @what@, splitting it into three
+ * pieces of sizes @sz0@, @sz1@, and @sz2@ respectively.  Block boundaries
+ * every @blksz@ bytes are shown consistency, independent of the split
+ * positions.
+ */
+static void dump_split(const char *what, size_t blksz, const octet *p,
+                      size_t sz0, size_t sz1, size_t sz2)
+{
+  printf("\t%-16s = ", what);
+  hexdump(p, sz0, 0, blksz);
+  if (sz1) { printf(", "); hexdump(p + sz0, sz1, sz0, blksz); }
+  if (sz2) { printf(", "); hexdump(p + sz0 + sz1, sz2, sz0 + sz1, blksz); }
+  fputc('\n', stdout);
+}
+
+/*----- Regression-data utilities -----------------------------------------*/
+
+/* Regression modes.  We can @CHECK@ existing data, @RECORD@ new data, or
+ * @IGNORE@ the regression testing entirely.
+ */
+enum { IGNORE, RECORD, CHECK };
+
+/* Read or write regression data from/to @fp@ according to @rmode@.  The data
+ * item is described as @what@ in diagnostic messages, and consists of @sz@
+ * bytes beginning at @p@.
+ *
+ * If @rmode@ is @IGNORE@, then this function does nothing; if @rmode@ is
+ * @RECORD@, then it writes @p@ to the output file with some framing; and if
+ * @rmode@ is @CHECK@ then it checks that the next chunk of data from the
+ * file matches @p@.
+ *
+ * Returns zero if all is well or @-1@ on a mismatch; I/O errors are fatal.
+ *
+ * Framing is trivial and consists of a 4-byte big-endian non-inclusive
+ * length prepended to each buffer.  No padding is written to maintain
+ * alignment.
+ */
+static int regress_data(int rmode, FILE *fp, const char *what,
+                       const void *p, size_t sz)
+{
+  octet b[4];
+  size_t psz;
+
+  switch (rmode) {
+    case IGNORE:
+      return (0);
+    case RECORD:
+      STORE32(b, sz);
+      if (!fwrite(b, 4, 1, fp) || !fwrite(p, sz, 1, fp))
+       die(1, "failed to write %s: %s", what, strerror(errno));
+      return (0);
+    case CHECK:
+      if (!fread(b, 4, 1, fp))
+       die(1, "failed to read %s length: %s", what,
+           ferror(fp) ? strerror(errno) : "unexpected eof");
+      psz = LOAD32(b);
+      if (psz != sz)
+       die(1, "incorrect %s length (%lu /= %lu; sync failure?)",
+           what, (unsigned long)psz, (unsigned long)sz);
+      if (tsz < sz) { xfree(t); t = xmalloc(sz); tsz = sz; }
+      if (!fread(t, sz, 1, fp))
+       die(1, "failed to read %s: %s", what,
+           ferror(fp) ? strerror(errno) : "unexpected eof");
+      if (memcmp(p, t, sz) != 0) return (-1);
+      return (0);
+    default:
+      abort();
+  }
+}
+
+/* Read or write framing data from/to @fp@ according to @rmode@.  The framing
+ * item is describd as @what@ in diagnostic messages, and consists of @sz@
+ * bytes beginning at @p@.
+ *
+ * Framing data is used to verify that a recorded regression-data file is
+ * still appropriate for use.  A fatal error is reported on any kind of
+ * failure.
+ */
+static void regress_framing(int rmode, FILE *fp, const char *what,
+                           const void *p, size_t sz)
+{
+  if (regress_data(rmode, fp, what, p, sz))
+    die(1, "regression framing mismatch for %s (bug, or wrong file)", what);
+}
+
+/* Read or write crypto data from/to @fp@ according to @rmode@.  The data
+ * item is describd as @what@ in diagnostic messages, and consists of the
+ * bytes beginning at @p@.  For the purposes of diagnostics, this buffer has
+ * been notionally split into three pieces, with sizes @sz0@, @sz1@, and
+ * @sz2@, respectively.
+ *
+ * If al is well, return zero.  If the crypto data doesn't match the recorded
+ * regression data, then report the mismatch, showing the way in which the
+ * buffer is split, and return -1.  I/O errors are fatal.
+ */
+static int regress_crypto(int rmode, FILE *fp, const char *what, size_t blksz,
+                         const void *p, size_t sz0, size_t sz1, size_t sz2)
+{
+  int rc;
+
+  rc = regress_data(rmode, fp, what, p, sz0 + sz1 + sz2);
+  if (rc) {
+    printf("\nRegression mismatch (split = %lu/%lu/%lu)\n",
+          (unsigned long)sz0, (unsigned long)sz1, (unsigned long)sz2);
+    dump_split("plaintext", blksz, text, sz0, sz1, sz2);
+    dump_split("expected ct", blksz, t, sz0, sz1, sz2);
+    dump_split("computed ct", blksz, p, sz0, sz1, sz2);
+    fputc('\n', stdout);
+  }
+  return (rc);
+}
+
+/*----- Selecting fragment sizes ------------------------------------------*/
+
+/* Return codes from @step@. */
+enum { STEP, LIMIT, RESET };
+
+/* Update @*sz_inout@ the next largest suitable fragment size, up to a
+ * maximum of @max@.
+ *
+ * If the new size is still smaller than the maximum, then return @STEP@.  If
+ * the size is maximal, then return @LIMIT@.  If the size was previously
+ * maximal already, then return @RESET@.
+ *
+ * The sizes here are selected powers of two, and powers of two plus or minus
+ * 1, with the objective of testing how internal buffering is affected when
+ * the cursor is misaligned and realigned with block boundaries.
+ */
+static int step(size_t *sz_inout, size_t max)
+{
+  size_t i;
+
+  static size_t steps[] = {   1,   7,   8,   9,  15,  16,  17,
+                                 63,  64,  65, 255, 256, 257 };
+
+  if (*sz_inout == max) return (RESET);
+  for (i = 0; i < N(steps); i++)
+    if (steps[i] > *sz_inout) {
+      if (steps[i] < max) { *sz_inout = steps[i]; return (STEP); }
+      else break;
+    }
+  *sz_inout = max; return (LIMIT);
+}
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @test_encmode@ --- *
+ *
+ * Arguments:  @const char *name@ = name of the encryption scheme; used to
+ *                     find the regression-test filename
+ *             @size_t ksz@ = key size to use, or zero for `don't care'
+ *             @size_t blksz@ = block size
+ *             @size_t minsz@ = smallest acceptable buffer size, or 1
+ *             @unsigned f@ = various additional flags
+ *             @setupfn *setup@ = key-setup function
+ *             @resetfn *reset@ = state-reset function
+ *             @encfn *enc@ = encryption function
+ *             @decfn *dec@ = decryption function
+ *             @int argc@ = number of command-line arguments
+ *             @char *argv@ = pointer to command-line argument vector
+ *
+ * Returns:    Zero on success, nonzero to report failure.
+ *
+ * Use:                Tests an encryption mode which doesn't have any more formal
+ *             test vectors.
+ *
+ *             The @name@ is used firstly in diagnostic output and secondly
+ *             to form the default filename to use for regression-test data,
+ *             as `.../symm/t/modes/NAME.regress'.
+ *
+ *             The key size @ksz@ is simply passed on back to the @setup@
+ *             function, unless the caller passes in zero, in which case
+ *             @test_encmode@ chooses a key size for itself.
+ *
+ *             The block size @blksz@ is used in failure reports, to draw
+ *             attention to the block structure in the various buffers,
+ *             which may assist with diagnosis.  It's also used to determine
+ *             when to apply a consistency check: see below regarding the
+ *             @TEMF_REFALIGN@ flag.
+ *
+ *             The minimum buffer size @minsz@ expresses a limitation on the
+ *             provided @enc@ and @dec@ functions, that they don't work on
+ *             inputs smaller than @minsz@; accordingly, @test_encmode@ will
+ *             not test such small sizes.  This should be 1 if the mode has
+ *             no limitation.
+ *
+ *             The flags @f@ influence testing in various ways explained
+ *             below.
+ *
+ *             The caller-provided functions are assumed to act on some
+ *             global but hidden state,
+ *
+ *               * @setup@ is (currently, at least) called only once, with
+ *                 the key @k@ and its chosen size @ksz@.
+ *
+ *               * @reset@ is called at the start of each encryption or
+ *                 decryption operation, to program in the initialization
+ *                 vector to use.  Currently, the same IV is used in all of
+ *                 the tests, but this might not always be the case.
+ *
+ *               * @enc@ is called to encrypt a source buffer @s@ and write
+ *                 the ciphertext to a destination @d@; @sz@ is the common
+ *                 size of these buffers.  @d@ might be null, to discard
+ *                 output; @s@ might be null, to process all-zero input.
+ *
+ *               * @dec@ is called to decrypt a source buffer @s@ and write
+ *                 the recovered plaintext to a destination @d@; @sz@ is the
+ *                 common size of these buffers.
+ *
+ *             Finally, @int argc@ and @char *argv@ are the command-line
+ *             arguments provided to @main@; @test_encmode@ parses these and
+ *             alters its behaviour accordingly.
+ *
+ *             Currently, @test_encmode@'s tests are built around a single,
+ *             fairly large, fixed message.  In each test step, the message
+ *             is split into a number of fragments which are encrypted and
+ *             decrypted in turn.
+ *
+ *             The following tests are performed.
+ *
+ *               * The fundamental `round-trip' test, which verifies that
+ *                 the message can be encrypted and then decrypted
+ *                 successfully, if the same fragment boundaries are used in
+ *                 both cases.
+ *
+ *               * A `consistency' test.  Some modes, such as CFB, OFB, and
+ *                 counter, are `resumable': encryption operations are
+ *                 insensitive to the position of fragment boundaries, so a
+ *                 single message can be broken into fragments without
+ *                 affecting the result.  If @TEMF_REFALIGN@ is clear then
+ *                 the mode under test is verified to have this property.
+ *                 If @TEMF_REFALIGN' is set, a weaker property is verified:
+ *                 that encryption is insensitive to the position of
+ *                 /block-aligned/ fragment boundaries only.
+ *
+ *               * A `regression' test, which verifies that the code
+ *                 produces the same ciphertext as a previous version.  By
+ *                 setting command-line arguments appropriately, a test
+ *                 program can be told to record ciphertexts in a (binary)
+ *                 data file.  Usually, instead, the program will read the
+ *                 recorded ciphertexts back and verify that it produces the
+ *                 same data.  For resumable modes, it's only necessary to
+ *                 record single ciphertext, since all the other ciphertexts
+ *                 must be equal by consistency; otherwise all non-block-
+ *                 aligned splits are recorded separately.
+ */
+
+int test_encmode(const char *name,
+                size_t ksz, size_t blksz, size_t minsz, unsigned f,
+                setupfn *setup, resetfn *reset, encfn *enc, encfn *dec,
+                int argc, char *argv[])
+{
+  int ok = 1, refp = 0, i;
+  size_t sz0, sz1, sz2;
+  const char spinner[] = "/-\\|";
+  int rmode = CHECK, spin = isatty(STDOUT_FILENO) ? 0 : -1;
+  int regr;
+  const char *rname = 0, *p;
+  FILE *fp;
+  dstr d = DSTR_INIT;
+
+  ego(argv[0]);
+
+  /* Parse the command-line options. */
+  p = 0; i = 1;
+  for (;;) {
+
+    /* Read the next argument. */
+    if (!p || !*p) {
+      if (i >= argc) break;
+      p = argv[i++];
+      if (strcmp(p, "--") == 0) break;
+      if (p[0] != '-' || p[1] == 0) { i--; break; }
+      p++;
+    }
+
+    /* Interpret an option. */
+    switch (*p++) {
+      case 'h':
+       printf("%s test driver\n"
+              "Usage: %s [-i] [-o|-f FILENAME]\n", QUIS, QUIS);
+       exit(0);
+      case 'i':
+       rmode = IGNORE;
+       break;
+      case 'o':
+       if (!*p) {
+         if (i >= argc) die(1, "option `-o' expects an argument");
+         p = argv[i++];
+       }
+       rmode = RECORD; rname = p; p = 0;
+       break;
+      case 'f':
+       if (!*p) {
+         if (i >= argc) die(1, "option `-f' expects an argument");
+         p = argv[i++];
+       }
+       rmode = CHECK; rname = p; p = 0;
+       break;
+      default:
+       die(1, "option `-%c' unknown", p[-1]);
+    }
+  }
+
+  /* Check there's nothing else left. */
+  if (i < argc) die(1, "trailing junk on command line");
+
+  /* Open the regression-data file. */
+  if (rmode == IGNORE)
+    fp = 0;
+  else {
+    if (!rname) {
+      DRESET(&d); dstr_putf(&d, SRCDIR"/t/modes/%s.regress", name);
+      rname = xstrdup(d.buf);
+    }
+    fp = fopen(rname, rmode == RECORD ? "wb" : "rb");
+    if (!fp)
+      die(1, "failed to open `%s' for %s: %s", rname,
+         rmode == RECORD ? "writing" : "reading", strerror(errno));
+  }
+
+  /* Write a header describing the file, to trap misuse for the wrong mode,
+   * and changes in the text.
+   */
+  DRESET(&d);
+  dstr_putf(&d, "mode=%s, text=%lu", name, (unsigned long)TEXTSZ);
+  regress_framing(rmode, fp, "header", d.buf, d.len);
+
+  /* Start things up. */
+  printf("%s: ", name);
+  setup(key, ksz ? ksz: sizeof(key));
+
+  /* Work through various sizes of up to three fragments.  The middle
+   * fragment is the important one, since it can be misaligned or not at
+   * either end.
+   */
+  sz0 = sz1 = minsz;
+  for (;;) {
+
+    /* If output is to a terminal then display a spinner to keep humans
+     * amused.
+     */
+    if (spin >= 0) {
+      printf("\r%s: [%c]\b\b", name, spinner[spin]); fflush(stdout);
+      spin = (spin + 1)&3;
+    }
+
+    /* Prepare for the test. */
+    sz2 = TEXTSZ - sz1 - sz0;
+    ok = 1;
+
+    /* Encrypt the last fragment first, to check discarding behaviour. */
+    if (sz2) {
+      reset(iv);
+      enc(text, 0, sz0);
+      enc(text + sz0, 0, sz1);
+      enc(text + sz0 + sz1, ct + sz0 + sz1, sz2);
+    }
+
+    /* Encrypt the first two fragments. */
+    reset(iv);
+    enc(text, ct, sz0);
+    if (sz1) {
+      memcpy(ct + sz0, text + sz0, sz1);
+      enc(ct + sz0, ct + sz0, sz1);
+    }
+
+    /* Try to check consistency.  We can't do this if (a) the mode is
+     * non-resumable and the fragments sizes are misaligned, or (b) this is
+     * our first pass through and we don't have a consistency reference yet.
+     *
+     * Also, decide whether to deploy the regression test, which we do if and
+     * only if we can't compare against the consistency reference.
+     */
+    regr = 0;
+    if ((f&TEMF_REFALIGN) && (sz0%blksz || sz1%blksz)) regr = 1;
+    else if (!refp) { memcpy(ref, ct, TEXTSZ); regr = 1; refp = 1; }
+    else if (memcmp(ref, ct, TEXTSZ) != 0) {
+      ok = 0;
+      printf("\nConsistency failure (split = %lu/%lu/%lu)\n",
+            (unsigned long)sz0, (unsigned long)sz1, (unsigned long)sz2);
+      dump_split("plaintext", blksz, text, sz0, sz1, sz2);
+      dump_split("reference", blksz, ref, sz0, sz1, sz2);
+      dump_split("ciphertext", blksz, ct, sz0, sz1, sz2);
+      fputc('\n', stdout);
+    }
+
+    /* If we need the regression test then do that.  Write a framing record
+     * to avoid confusion if the policy changes.
+     */
+    if (regr) {
+      DRESET(&d);
+      dstr_putf(&d, "split = %lu/%lu/%lu",
+               (unsigned long)sz0, (unsigned long)sz1, (unsigned long)sz2);
+      regress_framing(rmode, fp, "split", d.buf, d.len);
+      if (regress_crypto(rmode, fp, "regress", blksz, ct, sz0, sz1, sz2))
+       ok = 0;
+    }
+
+    /* Finally, decrypt and check that the round-trip works. */
+    reset(iv);
+    dec(ct, pt, sz0);
+    if (sz1) {
+      memcpy(pt + sz0, ct + sz0, sz1);
+      dec(pt + sz0, pt + sz0, sz1);
+    }
+    if (sz2)
+      dec(ct + sz0 + sz1, pt + sz0 + sz1, sz2);
+    if (memcmp(text, pt, TEXTSZ) != 0) {
+      ok = 0;
+      printf("\nRound-trip failure (split = %lu/%lu/%lu)\n",
+            (unsigned long)sz0, (unsigned long)sz1, (unsigned long)sz2);
+      dump_split("plaintext", blksz, text, sz0, sz1, sz2);
+      dump_split("ciphertext", blksz, ct, sz0, sz1, sz2);
+      dump_split("recovered", blksz, pt, sz0, sz1, sz2);
+      fputc('\n', stdout);
+    }
+
+    /* Update the fragment sizes. */
+    if (!sz1) break;
+    if (step(&sz1, TEXTSZ - sz0) == RESET) {
+      if (step(&sz0, TEXTSZ) == LIMIT) sz1 = 0;
+      else sz1 = minsz;
+    }
+  }
+
+  /* Close the regression data file. */
+  if (fp && (ferror(fp) || fclose(fp)))
+    die(1, "error closing `%s': %s", rname, strerror(errno));
+
+  /* Finish off the eyecandy spinner. */
+  if (spin >= 0) printf("\r%s: [%c] ", name, ok ? '*' : 'X');
+
+  /* Summarize the test result. */
+  if (ok) printf("ok\n");
+  else printf("failed\n");
+
+  /* And we're done. */
+  dstr_destroy(&d);
+  return (!ok);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/symm/modes-test.h b/symm/modes-test.h
new file mode 100644 (file)
index 0000000..83d35dc
--- /dev/null
@@ -0,0 +1,166 @@
+/* -*-c-*-
+ *
+ * Common testing for encryption modes
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_MODES_TEST_H
+#define CATACOMB_MODES_TEST_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* Functions used by `test_encmode' below. */
+typedef void setupfn(const octet */*k*/, size_t /*ksz*/);
+typedef void resetfn(const octet */*iv*/);
+typedef void encfn(const octet */*s*/, octet */*d*/, size_t /*sz*/);
+
+/*----- Functions provided ------------------------------------------------*/
+
+#define TEMF_REFALIGN 1u               /* misalignment of pieces affects
+                                        * the encryption state
+                                        */
+
+/* --- @test_encmode@ --- *
+ *
+ * Arguments:  @const char *name@ = name of the encryption scheme; used to
+ *                     find the regression-test filename
+ *             @size_t ksz@ = key size to use, or zero for `don't care'
+ *             @size_t blksz@ = block size
+ *             @size_t minsz@ = smallest acceptable buffer size, or 1
+ *             @unsigned f@ = various additional flags
+ *             @setupfn *setup@ = key-setup function
+ *             @resetfn *reset@ = state-reset function
+ *             @encfn *enc@ = encryption function
+ *             @decfn *dec@ = decryption function
+ *             @int argc@ = number of command-line arguments
+ *             @char *argv@ = pointer to command-line argument vector
+ *
+ * Returns:    Zero on success, nonzero to report failure.
+ *
+ * Use:                Tests an encryption mode which doesn't have any more formal
+ *             test vectors.
+ *
+ *             The @name@ is used firstly in diagnostic output and secondly
+ *             to form the default filename to use for regression-test data,
+ *             as `.../symm/t/modes/NAME.regress'.
+ *
+ *             The key size @ksz@ is simply passed on back to the @setup@
+ *             function, unless the caller passes in zero, in which case
+ *             @test_encmode@ chooses a key size for itself.
+ *
+ *             The block size @blksz@ is used in failure reports, to draw
+ *             attention to the block structure in the various buffers,
+ *             which may assist with diagnosis.  It's also used to determine
+ *             when to apply a consistency check: see below regarding the
+ *             @TEMF_REFALIGN@ flag.
+ *
+ *             The minimum buffer size @minsz@ expresses a limitation on the
+ *             provided @enc@ and @dec@ functions, that they don't work on
+ *             inputs smaller than @minsz@; accordingly, @test_encmode@ will
+ *             not test such small sizes.  This should be 1 if the mode has
+ *             no limitation.
+ *
+ *             The flags @f@ influence testing in various ways explained
+ *             below.
+ *
+ *             The caller-provided functions are assumed to act on some
+ *             global but hidden state,
+ *
+ *               * @setup@ is (currently, at least) called only once, with
+ *                 the key @k@ and its chosen size @ksz@.
+ *
+ *               * @reset@ is called at the start of each encryption or
+ *                 decryption operation, to program in the initialization
+ *                 vector to use.  Currently, the same IV is used in all of
+ *                 the tests, but this might not always be the case.
+ *
+ *               * @enc@ is called to encrypt a source buffer @s@ and write
+ *                 the ciphertext to a destination @d@; @sz@ is the common
+ *                 size of these buffers.  @d@ might be null, to discard
+ *                 output; @s@ might be null, to process all-zero input.
+ *
+ *               * @dec@ is called to decrypt a source buffer @s@ and write
+ *                 the recovered plaintext to a destination @d@; @sz@ is the
+ *                 common size of these buffers.
+ *
+ *             Finally, @int argc@ and @char *argv@ are the command-line
+ *             arguments provided to @main@; @test_encmode@ parses these and
+ *             alters its behaviour accordingly.
+ *
+ *             Currently, @test_encmode@'s tests are built around a single,
+ *             fairly large, fixed message.  In each test step, the message
+ *             is split into a number of fragments which are encrypted and
+ *             decrypted in turn.
+ *
+ *             The following tests are performed.
+ *
+ *               * The fundamental `round-trip' test, which verifies that
+ *                 the message can be encrypted and then decrypted
+ *                 successfully, if the same fragment boundaries are used in
+ *                 both cases.
+ *
+ *               * A `consistency' test.  Some modes, such as CFB, OFB, and
+ *                 counter, are `resumable': encryption operations are
+ *                 insensitive to the position of fragment boundaries, so a
+ *                 single message can be broken into fragments without
+ *                 affecting the result.  If @TEMF_REFALIGN@ is clear then
+ *                 the mode under test is verified to have this property.
+ *                 If @TEMF_REFALIGN' is set, a weaker property is verified:
+ *                 that encryption is insensitive to the position of
+ *                 /block-aligned/ fragment boundaries only.
+ *
+ *               * A `regression' test, which verifies that the code
+ *                 produces the same ciphertext as a previous version.  By
+ *                 setting command-line arguments appropriately, a test
+ *                 program can be told to record ciphertexts in a (binary)
+ *                 data file.  Usually, instead, the program will read the
+ *                 recorded ciphertexts back and verify that it produces the
+ *                 same data.  For resumable modes, it's only necessary to
+ *                 record single ciphertext, since all the other ciphertexts
+ *                 must be equal by consistency; otherwise all non-block-
+ *                 aligned splits are recorded separately.
+ */
+
+extern int test_encmode(const char */*name*/,
+                       size_t /*ksz*/, size_t /*blksz*/,
+                       size_t /*minsz */, unsigned /*f*/,
+                       setupfn */*setup*/, resetfn */*reset*/,
+                       encfn */*enc*/, encfn */*dec*/,
+                       int /*argc*/, char */*argv*/[]);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index 395d06f..d95a5f1 100644 (file)
@@ -61,9 +61,18 @@ CIPHER_MODES += @{blkc:f}-@blkcciphermode
 CIPHER_MODES += @{hash:f}-@hashciphermode
 %end
 
+## Modes for authenticated encryption.
+AEAD_MODES =
+%repeat
+AEAD_MODES += @{blkc:f}-@blkcaeadmode
+%end
+
 ## Modes for message authentication.
 MAC_MODES =
 %repeat
+MAC_MODES += @{blkc:f}-@blkcmacmode
+%end
+%repeat
 MAC_MODES += @{hash:f}-@hashmacmode
 %end
 
@@ -75,3 +84,12 @@ SYMM_TEST_FILES += t/@{blkc:f}
 %repeat
 SYMM_TEST_FILES += t/@{hash:f}
 %end
+
+## Regression-test files.
+REGRESSION_TEST_FILES =
+%repeat
+REGRESSION_TEST_FILES += t/modes/@{blkc:f}-@{blkcciphermode}.regress
+%end
+%repeat
+REGRESSION_TEST_FILES += t/modes/@{hash:f}-@{hashciphermode}.regress
+%end
diff --git a/symm/ocb.c b/symm/ocb.c
new file mode 100644 (file)
index 0000000..1c97215
--- /dev/null
@@ -0,0 +1,73 @@
+/* -*-c-*-
+ *
+ * Common definitions for OCB and related modes
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include "ocb.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @ocb_ctz@, @ocb_ctzl@ --- *
+ *
+ * Arguments:  @unsigned i@ or @unsigned long i@ = operand, assumed nonzero
+ *
+ * Returns:    The number of trailing zero bits in @i@, or nonsense if
+ *             %$i = 0$%.
+ */
+
+unsigned ocb_ctz(unsigned i)
+{
+  unsigned n = 0;
+
+  if (!(i&0x00ff)) { n +=  8; i >>=  8; }
+  if (!(i&0x000f)) { n +=  4; i >>=  4; }
+  if (!(i&0x0003)) { n +=  2; i >>=  2; }
+  if (!(i&0x0001)) { n +=  1; i >>=  1; }
+  return (n);
+}
+
+unsigned ocb_ctzl(unsigned long i)
+{
+  unsigned n = 0;
+
+#if ULONG_BITS > 64
+  while (!(i&0xfffffffffffffffful)) { n += 64; i >>= 64; }
+#endif
+#if ULONG_BITS > 32
+  if (!(i&0xffffffff)) { n += 32; i >>= 32; }
+#endif
+  if (!(i&0xffff)) { n += 16; i >>= 16; }
+  if (!(i&0x00ff)) { n +=  8; i >>=  8; }
+  if (!(i&0x000f)) { n +=  4; i >>=  4; }
+  if (!(i&0x0003)) { n +=  2; i >>=  2; }
+  if (!(i&0x0001)) { n +=  1; i >>=  1; }
+  return (n);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/symm/ocb.h b/symm/ocb.h
new file mode 100644 (file)
index 0000000..d87aed3
--- /dev/null
@@ -0,0 +1,117 @@
+/* -*-c-*-
+ *
+ * Common definitions for OCB and related modes
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_OCB_H
+#define CATACOMB_OCB_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/compiler.h>
+
+/*----- Constants ---------------------------------------------------------*/
+
+/* The number of offsets to maintain.  Rather than calculate and store all
+ * possible offset values in advance, or calculate new ones on demand (and
+ * have to allocate space for them), we calculate a number in advance, and
+ * determine any others every time they're needed.  If we calculate the first
+ * %$n$% offsets only, then we spend %$i - n + 1$% time calculating offset
+ * %$L_i$% when %$i \ge n$%.  But the offset %$L_i$% is used only for a
+ * %$2^{-i-1}$% fraction of the blocks.  Summing up this geometric series
+ * shows us that we add only a small constant overhead, and save storage
+ * space for many offsets.
+ */
+#define OCB_NCALC 16
+#define OCB_CALCMASK ((1ul << OCB_NCALC) - 1)
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @ocb_ctz@, @ocb_ctzl@ --- *
+ *
+ * Arguments:  @unsigned i@ or @unsigned long i@ = operand, assumed nonzero
+ *
+ * Returns:    The number of trailing zero bits in @i@, or nonsense if
+ *             %$i = 0$%.
+ */
+
+extern unsigned ocb_ctz(unsigned /*i*/);
+extern unsigned ocb_ctzl(unsigned long /*i*/);
+
+#if GCC_VERSION_P(3, 4)
+#  define OCB_CTZ(i) __builtin_ctz(i)
+#  define OCB_CTZL(i) __builtin_ctzl(i)
+#else
+#  define OCB_CTZ(i) ocb_ctz(i)
+#  define OCB_CTZL(i) ocb_ctzl(i)
+#endif
+
+/* --- @OCB_OFFSET@ --- *
+ *
+ * Arguments:  @PRE@ = block cipher prefix
+ *             @uint32 *o@ = pointer to offset accumulator
+ *             @uint32 (*l)[PRE_BLKSZ]@ = pointer to offset mask table
+ *             @unsigned long i@ = block index
+ *
+ * Returns:    ---
+ *
+ * Use:                Update the per-block offset for Grey-code-based OCB
+ *             variants.  On entry, @o@ is assumed to hold the offset for
+ *             block @i - 1@; on exit @o@ is updated to hold the offset for
+ *             block @i@.
+ */
+
+#define OCB_OFFSET(PRE, o, l, i) do {                                  \
+  uint32 (*_l)[PRE##_BLKSZ/4] = (l);                                   \
+  uint32 *_o = (o);                                                    \
+  unsigned long _i = (i);                                              \
+  unsigned _j;                                                         \
+                                                                       \
+  if (_i&OCB_CALCMASK) {                                               \
+    _j = OCB_CTZ(_i);                                                  \
+    BLKC_XMOVE(PRE, _o, _l[_j]);                                       \
+  } else {                                                             \
+    uint32 _t[PRE##_BLKSZ];                                            \
+    _j = OCB_CTZL(_i) - OCB_NCALC;                                     \
+    BLKC_BLSHIFT(PRE, IRRED, _t, _l[OCB_NCALC - 1]);                   \
+    while (_j--) BLKC_BLSHIFT(PRE, IRRED, _t, _t);                     \
+    BLKC_XMOVE(PRE, _t, _l[_j]);                                       \
+  }                                                                    \
+} while (0)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/ocb1-def.h b/symm/ocb1-def.h
new file mode 100644 (file)
index 0000000..7c7eb29
--- /dev/null
@@ -0,0 +1,670 @@
+/* -*-c-*-
+ *
+ * The OCB1 authenticated encryption mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_OCB1_DEF_H
+#define CATACOMB_OCB1_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_BLKC_H
+#  include "blkc.h"
+#endif
+
+#ifndef CATACOMB_CT_H
+#  include "ct.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+#  include "keysz.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @OCB1_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates an implementation for the OCB1 authenticated-
+ *             encryption mode.
+ */
+
+#define OCB1_DEF(PRE, pre) OCB1_DEFX(PRE, pre, #pre, #pre)
+
+#define OCB1_DEFX(PRE, pre, name, fname)                               \
+                                                                       \
+const octet                                                            \
+  pre##_ocb1noncesz[] = { KSZ_SET, PRE##_BLKSZ, 0 },                   \
+  pre##_ocb1tagsz[] = { KSZ_RANGE, PRE##_BLKSZ, 0, PRE##_BLKSZ, 1 };   \
+                                                                       \
+/* --- @pre_ocb1init@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 context            \
+ *             @const pre_ocb1key *key@ = pointer to key block         \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce length is bad.       \
+ *                                                                     \
+ * Use:                Initialize an OCB1 operation context with a given key.  \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+int pre##_ocb1init(pre##_ocb1ctx *ctx, const pre##_ocb1key *k,         \
+                   const void *n, size_t nsz)                          \
+  { ctx->k = *k; return (pre##_ocb1reinit(ctx, n, nsz)); }             \
+                                                                       \
+/* --- @pre_ocb1reinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 context            \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce length is bad.       \
+ *                                                                     \
+ * Use:                Reinitialize an OCB1 operation context, changing the    \
+ *             nonce.                                                  \
+ */                                                                    \
+                                                                       \
+int pre##_ocb1reinit(pre##_ocb1ctx *ctx, const void *n, size_t nsz)    \
+{                                                                      \
+  if (nsz != PRE##_BLKSZ) return (-1);                                 \
+  ctx->off = 0; BLKC_ZERO(PRE, ctx->a);                                        \
+  BLKC_LOAD(PRE, ctx->o, n); BLKC_XMOVE(PRE, ctx->o, ctx->k.lmask[0]); \
+  pre##_eblk(&ctx->k.ctx, ctx->o, ctx->o); ctx->i = 1;                 \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb1encrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 operation context  \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB1 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+int pre##_ocb1encrypt(pre##_ocb1ctx *ctx,                              \
+                     const void *src, size_t sz, buf *dst)             \
+{                                                                      \
+  rsvr_state st;                                                       \
+  size_t osz;                                                          \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *p;                                                      \
+  octet *q;                                                            \
+                                                                       \
+  /* Figure out what we're going to do. */                             \
+  rsvr_setup(&st, &pre##_ocb1policy, ctx->b, &ctx->off, src, sz);      \
+                                                                       \
+  /* Determine the output size and verify that there is enough         \
+   * space.                                                            \
+   */                                                                  \
+  osz = st.plan.from_rsvr + st.plan.from_input;                                \
+  if (!osz) q = 0;                                                     \
+  else { q = buf_get(dst, osz); if (!q) return (-1); }                 \
+                                                                       \
+  /* Process the input in whole blocks at a time. */                   \
+  RSVR_DO(&st) while ((p = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    OCB_OFFSET(PRE, ctx->o, ctx->k.lmask, ctx->i++);                   \
+    BLKC_LOAD(PRE, t, p); BLKC_XMOVE(PRE, ctx->a, t);                  \
+    BLKC_XMOVE(PRE, t, ctx->o); pre##_eblk(&ctx->k.ctx, t, t);         \
+    BLKC_XSTORE(PRE, q, t, ctx->o); q += PRE##_BLKSZ;                  \
+  }                                                                    \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb1decrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 operation context  \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB1 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+int pre##_ocb1decrypt(pre##_ocb1ctx *ctx,                              \
+                     const void *src, size_t sz, buf *dst)             \
+{                                                                      \
+  rsvr_state st;                                                       \
+  size_t osz;                                                          \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *p;                                                      \
+  octet *q;                                                            \
+                                                                       \
+  /* Figure out what we're going to do. */                             \
+  rsvr_setup(&st, &pre##_ocb1policy, ctx->b, &ctx->off, src, sz);      \
+                                                                       \
+  /* Determine the output size and verify that there is enough         \
+   * space.                                                            \
+   */                                                                  \
+  osz = st.plan.from_rsvr + st.plan.from_input;                                \
+  if (!osz) q = 0;                                                     \
+  else { q = buf_get(dst, osz); if (!q) return (-1); }                 \
+                                                                       \
+  /* Process the input in whole blocks at a time. */                   \
+  RSVR_DO(&st) while ((p = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    OCB_OFFSET(PRE, ctx->o, ctx->k.lmask, ctx->i++);                   \
+    BLKC_LOAD(PRE, t, p);                                              \
+    BLKC_XMOVE(PRE, t, ctx->o); pre##_dblk(&ctx->k.ctx, t, t);         \
+    BLKC_XMOVE(PRE, t, ctx->o); BLKC_XMOVE(PRE, ctx->a, t);            \
+    BLKC_STORE(PRE, q, t); q += PRE##_BLKSZ;                           \
+  }                                                                    \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb1encdecfinal@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to an OCB1 context         \
+ *             @const pre_ocb1aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @int encp@ = nonzero if we're encrypting                \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Common end-of-message handling for encryption and       \
+ *             decryption.  The full-length tag is left in the         \
+ *             context's buffer.                                       \
+ */                                                                    \
+                                                                       \
+static int pre##_ocb1encdecfinal(pre##_ocb1ctx *ctx,                   \
+                                const pre##_ocb1aadctx *aad, buf *dst, \
+                                int encp)                              \
+{                                                                      \
+  octet *q;                                                            \
+                                                                       \
+  /* Arrange space for the final output (if any). */                   \
+  if (!ctx->off) { q = 0; if (!BOK(dst)) return (-1); }                        \
+  else { q = buf_get(dst, ctx->off); if (!q) return (-1); }            \
+                                                                       \
+  /* Calculate the final offset.  Mix it into the checksum before it   \
+   * gets clobbered.                                                   \
+   */                                                                  \
+  OCB_OFFSET(PRE, ctx->o, ctx->k.lmask, ctx->i++);                     \
+  BLKC_XMOVE(PRE, ctx->a, ctx->o);                                     \
+                                                                       \
+  /* Mix the magic final mask and tail length into the offset. */      \
+  BLKC_XMOVE(PRE, ctx->o, ctx->k.lxinv);                               \
+  ctx->o[PRE##_BLKSZ/4 - 1] ^= BLKC_BWORD(PRE, 8*ctx->off);            \
+                                                                       \
+  /* If we're decrypting, then trim the end of the plaintext and fold  \
+   * that into the checksum.                                           \
+   */                                                                  \
+  if (!encp) {                                                         \
+    memset(ctx->b + ctx->off, 0, PRE##_BLKSZ - ctx->off);              \
+    BLKC_XLOAD(PRE, ctx->a, ctx->b);                                   \
+  }                                                                    \
+                                                                       \
+  /* Cycle the block cipher for the last plaintext block. */           \
+  pre##_eblk(&ctx->k.ctx, ctx->o, ctx->o);                             \
+                                                                       \
+  /* Fold this mask into the checksum before it gets clobbered. */     \
+  BLKC_XMOVE(PRE, ctx->a, ctx->o);                                     \
+                                                                       \
+  /* Encrypt the message tail. */                                      \
+  BLKC_XLOAD(PRE, ctx->o, ctx->b);                                     \
+  BLKC_STORE(PRE, ctx->b, ctx->o);                                     \
+  if (ctx->off) memcpy(q, ctx->b, ctx->off);                           \
+                                                                       \
+  /* If we're encrypting, then trim the end of the ciphertext and fold \
+   * that into the checksum.                                           \
+   */                                                                  \
+  if (encp) {                                                          \
+    memset(ctx->b + ctx->off, 0, PRE##_BLKSZ - ctx->off);              \
+    BLKC_XLOAD(PRE, ctx->a, ctx->b);                                   \
+  }                                                                    \
+                                                                       \
+  /* Encrypt the checksum to produce a tag. */                         \
+  pre##_eblk(&ctx->k.ctx, ctx->a, ctx->a);                             \
+                                                                       \
+  /* If there's AAD then mix the PMAC tag in too. */                   \
+  if (aad && aad->off)                                                 \
+    { pre##_ocb1aadtag(aad, ctx->o); BLKC_XMOVE(PRE, ctx->a, ctx->o); } \
+                                                                       \
+  /* Write the final tag. */                                           \
+  BLKC_STORE(PRE, ctx->b, ctx->a);                                     \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb1encryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to an OCB1 context         \
+ *             @const pre_ocb1aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an OCB1 encryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB1 delays output, so this will   \
+ *             cause any remaining buffered plaintext to be encrypted  \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+int pre##_ocb1encryptdone(pre##_ocb1ctx *ctx,                          \
+                         const pre##_ocb1aadctx *aad, buf *dst,        \
+                         void *tag, size_t tsz)                        \
+{                                                                      \
+  assert(tsz <= PRE##_BLKSZ);                                          \
+  if (pre##_ocb1encdecfinal(ctx, aad, dst, 1)) return (-1);            \
+  memcpy(tag, ctx->b, tsz);                                            \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb1decryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to an OCB1 context         \
+ *             @const pre_ocb1aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an OCB1 decryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB1 delays output, so this will   \
+ *             cause any remaining buffered ciphertext to be decrypted \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+int pre##_ocb1decryptdone(pre##_ocb1ctx *ctx,                          \
+                         const pre##_ocb1aadctx *aad, buf *dst,        \
+                         const void *tag, size_t tsz)                  \
+{                                                                      \
+  assert(tsz <= PRE##_BLKSZ);                                          \
+  if (pre##_ocb1encdecfinal(ctx, aad, dst, 0)) return (-1);            \
+  else if (ct_memeq(tag, ctx->b, tsz)) return (+1);                    \
+  else return (0);                                                     \
+}                                                                      \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+typedef struct gactx {                                                 \
+  gaead_aad a;                                                         \
+  pre##_ocb1aadctx aad;                                                        \
+} gactx;                                                               \
+                                                                       \
+static gaead_aad *gadup(const gaead_aad *a)                                    \
+  { gactx *aad = S_CREATE(gactx); *aad = *(gactx *)a; return (&aad->a); } \
+                                                                       \
+static void gahash(gaead_aad *a, const void *h, size_t hsz)            \
+  { gactx *aad = (gactx *)a; pre##_ocb1aadhash(&aad->aad, h, hsz); }   \
+                                                                       \
+static void gadestroy(gaead_aad *a)                                    \
+  { gactx *aad = (gactx *)a; BURN(*aad); S_DESTROY(aad); }             \
+                                                                       \
+static const gaead_aadops gaops =                                      \
+  { &pre##_ocb1, gadup, gahash, gadestroy };                           \
+                                                                       \
+static gaead_aad *gaad(const pre##_ocb1key *k)                         \
+{                                                                      \
+  gactx *aad = S_CREATE(gactx);                                                \
+  aad->a.ops = &gaops;                                                 \
+  pre##_ocb1aadinit(&aad->aad, k);                                     \
+  return (&aad->a);                                                    \
+}                                                                      \
+                                                                       \
+typedef struct gectx {                                                 \
+  gaead_enc e;                                                         \
+  pre##_ocb1ctx ctx;                                                   \
+} gectx;                                                               \
+                                                                       \
+static gaead_aad *geaad(gaead_enc *e)                                  \
+  { gectx *enc = (gectx *)e; return (gaad(&enc->ctx.k)); }             \
+                                                                       \
+static int gereinit(gaead_enc *e, const void *n, size_t nsz,           \
+                    size_t hsz, size_t msz, size_t tsz)                \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_ocb1reinit(&enc->ctx, n, nsz));                                \
+}                                                                      \
+                                                                       \
+static int geenc(gaead_enc *e, const void *m, size_t msz, buf *b)      \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_ocb1encrypt(&enc->ctx, m, msz, b));                    \
+}                                                                      \
+                                                                       \
+static int gedone(gaead_enc *e, const gaead_aad *a,                    \
+                 buf *b, void *t, size_t tsz)                          \
+{                                                                      \
+  gectx *enc = (gectx *)e; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_ocb1encryptdone(&enc->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gedestroy(gaead_enc *e)                                    \
+  { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); }             \
+                                                                       \
+static const gaead_encops geops =                                      \
+  { &pre##_ocb1, geaad, gereinit, geenc, gedone, gedestroy };          \
+                                                                       \
+typedef struct gdctx {                                                 \
+  gaead_dec d;                                                         \
+  pre##_ocb1ctx ctx;                                                   \
+} gdctx;                                                               \
+                                                                       \
+static gaead_aad *gdaad(gaead_dec *d)                                  \
+  { gdctx *dec = (gdctx *)d; return (gaad(&dec->ctx.k)); }             \
+                                                                       \
+static int gdreinit(gaead_dec *d, const void *n, size_t nsz,           \
+                    size_t hsz, size_t csz, size_t tsz)                \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_ocb1reinit(&dec->ctx, n, nsz));                                \
+}                                                                      \
+                                                                       \
+static int gddec(gaead_dec *d, const void *c, size_t csz, buf *b)      \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_ocb1decrypt(&dec->ctx, c, csz, b));                    \
+}                                                                      \
+                                                                       \
+static int gddone(gaead_dec *d, const gaead_aad *a,                    \
+                 buf *b, const void *t, size_t tsz)                    \
+{                                                                      \
+  gdctx *dec = (gdctx *)d; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_ocb1decryptdone(&dec->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gddestroy(gaead_dec *d)                                    \
+  { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); }             \
+                                                                       \
+static const gaead_decops gdops =                                      \
+  { &pre##_ocb1, gdaad, gdreinit, gddec, gddone, gddestroy };          \
+                                                                       \
+typedef struct gkctx {                                                 \
+  gaead_key k;                                                         \
+  pre##_ocb1key key;                                                   \
+} gkctx;                                                               \
+                                                                       \
+static gaead_aad *gkaad(const gaead_key *k)                            \
+  { gkctx *key = (gkctx *)k; return (gaad(&key->key)); }               \
+                                                                       \
+static gaead_enc *gkenc(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t msz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gectx *enc = S_CREATE(gectx);                                                \
+                                                                       \
+  enc->e.ops = &geops;                                                 \
+  if (pre##_ocb1init(&enc->ctx, &key->key, n, nsz))                    \
+    { gedestroy(&enc->e); return (0); }                                        \
+  return (&enc->e);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_dec *gkdec(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t csz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gdctx *dec = S_CREATE(gdctx);                                                \
+                                                                       \
+  dec->d.ops = &gdops;                                                 \
+  if (pre##_ocb1init(&dec->ctx, &key->key, n, nsz))                    \
+    { gddestroy(&dec->d); return (0); }                                        \
+  return (&dec->d);                                                    \
+}                                                                      \
+                                                                       \
+static void gkdestroy(gaead_key *k)                                    \
+  { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); }             \
+                                                                       \
+static const gaead_keyops gkops =                                      \
+  { &pre##_ocb1, gkaad, gkenc, gkdec, gkdestroy };                     \
+                                                                       \
+static gaead_key *gckey(const void *k, size_t ksz)                     \
+{                                                                      \
+  gkctx *key = S_CREATE(gkctx);                                                \
+  key->k.ops = &gkops;                                                 \
+  pre##_ocb1setkey(&key->key, k, ksz);                                 \
+  return (&key->k);                                                    \
+}                                                                      \
+                                                                       \
+const gcaead pre##_ocb1 = {                                            \
+  name "-ocb1",                                                                \
+  pre##_keysz, pre##_ocb1noncesz, pre##_ocb1tagsz,                     \
+  PRE##_BLKSZ, PRE##_BLKSZ, 0, 0,                                      \
+  gckey                                                                        \
+};                                                                     \
+                                                                       \
+OCB1_TESTX(PRE, pre, name, fname)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#define OCB1_TEST(PRE, pre) OCB1_TESTX(PRE, pre, #pre, #pre)
+
+/* --- @OCB1_TEST@ --- *
+ *
+ * Arguments:  @PRE, pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Standard test rig for OCB1 functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define OCB1_TESTX(PRE, pre, name, fname)                              \
+                                                                       \
+static int ocb1verify(dstr *v)                                         \
+{                                                                      \
+  pre##_ocb1key key;                                                   \
+  pre##_ocb1aadctx aad;                                                        \
+  pre##_ocb1ctx ctx;                                                   \
+  int ok = 1, win;                                                     \
+  int i;                                                               \
+  octet *p;                                                            \
+  int szs[] = { 1, 7, 192, -1, 0 }, *ip;                               \
+  size_t hsz, msz;                                                     \
+  dstr d = DSTR_INIT, t = DSTR_INIT;                                   \
+  buf b;                                                               \
+                                                                       \
+  dstr_ensure(&d, v[4].len > v[3].len ? v[4].len : v[3].len);          \
+  dstr_ensure(&t, v[5].len); t.len = v[5].len;                         \
+                                                                       \
+  pre##_ocb1setkey(&key, v[0].buf, v[0].len);                          \
+                                                                       \
+  for (ip = szs; *ip; ip++) {                                          \
+                                                                       \
+    pre##_ocb1init(&ctx, &key, (octet *)v[1].buf, v[1].len);           \
+                                                                       \
+    i = *ip;                                                           \
+    hsz = v[2].len;                                                    \
+    if (i == -1) i = hsz;                                              \
+    if (i > hsz) continue;                                             \
+    p = (octet *)v[2].buf;                                             \
+    pre##_ocb1aadinit(&aad, &key);                                     \
+    while (hsz) {                                                      \
+      if (i > hsz) i = hsz;                                            \
+      pre##_ocb1aadhash(&aad, p, i);                                   \
+      p += i; hsz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[3].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[3].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_ocb1encrypt(&ctx, p, i, &b)) {                         \
+       puts("!! ocb1encrypt reports failure");                         \
+       goto fail_enc;                                                  \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    if (pre##_ocb1encryptdone(&ctx, &aad, &b, (octet *)t.buf, t.len)) {        \
+      puts("!! ocb1encryptdone reports failure");                      \
+      goto fail_enc;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[4].len ||                                           \
+       memcmp(d.buf, v[4].buf, v[4].len) != 0 ||                       \
+       memcmp(t.buf, v[5].buf, v[5].len) != 0) {                       \
+    fail_enc:                                                          \
+      printf("\nfail encrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tmessage = ", stdout); type_hex.dump(&v[3], stdout);   \
+      fputs("\n\texp ct = ", stdout); type_hex.dump(&v[4], stdout);    \
+      fputs("\n\tcalc ct = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\texp tag = ", stdout); type_hex.dump(&v[5], stdout);   \
+      fputs("\n\tcalc tag = ", stdout); type_hex.dump(&t, stdout);     \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+                                                                       \
+    pre##_ocb1init(&ctx, &key, (octet *)v[1].buf, v[1].len);           \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[4].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[4].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_ocb1decrypt(&ctx, p, i, &b)) {                         \
+       puts("!! ocb1decrypt reports failure");                         \
+       win = 0; goto fail_dec;                                         \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    win = pre##_ocb1decryptdone(&ctx, &aad, &b,                                \
+                              (octet *)v[5].buf, v[5].len);            \
+    if (win < 0) {                                                     \
+      puts("!! ocb1decryptdone reports failure");                      \
+      goto fail_dec;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[3].len || !win ||                                   \
+       memcmp(d.buf, v[3].buf, v[3].len) != 0) {                       \
+    fail_dec:                                                          \
+      printf("\nfail decrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tciphertext = ", stdout); type_hex.dump(&v[4], stdout);        \
+      fputs("\n\texp pt = ", stdout); type_hex.dump(&v[3], stdout);    \
+      fputs("\n\tcalc pt = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\ttag = ", stdout); type_hex.dump(&v[5], stdout);       \
+      printf("\n\tverify %s", win ? "ok" : "FAILED");                  \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  dstr_destroy(&d); dstr_destroy(&t);                                  \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static test_chunk aeaddefs[] = {                                       \
+  { name "-ocb1", ocb1verify,                                          \
+    { &type_hex, &type_hex, &type_hex, &type_hex,                      \
+      &type_hex, &type_hex, 0 } },                                     \
+  { 0, 0, { 0 } }                                                      \
+};                                                                     \
+                                                                       \
+int main(int argc, char *argv[])                                       \
+{                                                                      \
+  ego(argv[0]);                                                                \
+  test_run(argc, argv, aeaddefs, SRCDIR"/t/" fname);                   \
+  return (0);                                                          \
+}
+
+#else
+#  define OCB1_TESTX(PRE, pre, name, fname)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/ocb1.h b/symm/ocb1.h
new file mode 100644 (file)
index 0000000..42cfb81
--- /dev/null
@@ -0,0 +1,345 @@
+/* -*-c-*-
+ *
+ * The OCB1 authenticated encryption mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Notes on OCB1 -----------------------------------------------------*
+ *
+ * OCB was designed in 2001 by Phillip Rogaway, with Mihir Bellare and John
+ * Black, as a blockcipher-based authenticated encryption scheme which can
+ * operate on multiple message blocks in parallel and requires only a single
+ * blockcipher application per message block.  It refines Charanjit Jutla's
+ * earlier IAPM, which was the first such mode to be proven secure.  This
+ * version implements the `OCB.PMAC' mode described by Rogaway in 2002, which
+ * combines the original OCB with PMAC (Rogaway and Black, 2002) into a
+ * single authenticated-encryption with associated-data (AEAD) scheme.
+ *
+ * The patent situation on these efficient authenticated encryption schemes
+ * is fraught.  IBM hold two patents on Jutla's pioneering work on `IACBC'
+ * and `IAPM' which can apply (a third was filed at least six years too
+ * late), and Virgil Gligor and Pompiliu Donescu hold patents on their `XECB'
+ * and `XCBC' modes; these may or may not apply to OCB.  Rogaway himself
+ * holds US patents on various versions of OCB, but has issued free licences
+ * for free (`open source') software, and for all non-military use.  I think
+ * Catacomb's implementation of OCB falls within the scope of the former
+ * licence.
+ *
+ * Confusingly, Rogaway's 2004 paper `Efficient Instantiations of Tweakable
+ * Blockciphers and Refinements to Modes OCB and PMAC' named the new versions
+ * of those modes `OCB1' and `PMAC1'.  The 2011 paper by Krovetz and Rogaway,
+ * `The Software Performance of Authenticated-Encryption Modes' renamed the
+ * original 2001 version of OCB as `OCB1', and the 2004 version `OCB2', and
+ * introduced a new `OCB3'.  I've decided to follow and extend the 2011
+ * naming, so `OCB1' refers to the 2001 OCB; the 2004 version would be
+ * `OCB2'.
+ *
+ * The OCB specification is clear about how OCB applies to arbitrary block
+ * sizes.
+ *
+ * OCB1 is a fairly well-behaved AEAD mode.  It doesn't require
+ * precommentment to any lengths, and allows header data to be processed
+ * independently of any message.  On the other hand, it only accepts nonces
+ * the same size as the underlying blockcipher's block size, and it buffers
+ * up to a whole block's worth of data internally, which somewhat complicates
+ * streaming.
+ */
+
+#ifndef CATACOMB_OCB1_H
+#define CATACOMB_OCB1_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+#ifndef CATACOMB_OCB_H
+#  include "ocb.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @OCB1_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates declarations for OCB1 message-authentication mode.
+ */
+
+#define OCB1_STRUCTS(PRE, pre, keyty, aadty)                           \
+                                                                       \
+typedef struct keyty {                                                 \
+  pre##_ctx ctx;                       /* Underlying cipher context */ \
+  uint32 lxinv[PRE##_BLKSZ/4];         /* Final-block mask */          \
+  uint32 lmask[OCB_NCALC][PRE##_BLKSZ/4]; /* Precalculated masks */    \
+} keyty;                                                               \
+                                                                       \
+typedef struct aadty {                                                 \
+  keyty k;                             /* Processed key material */    \
+  uint32 o[PRE##_BLKSZ/4];             /* Current offset */            \
+  uint32 a[PRE##_BLKSZ/4];             /* Accumulator state */         \
+  octet b[PRE##_BLKSZ];                        /* Input buffer */              \
+  unsigned long i;                     /* Block counter */             \
+  unsigned off;                                /* Offset into buffered data */ \
+} aadty;
+
+#define OCB1_DECL(PRE, pre)                                            \
+                                                                       \
+OCB1_STRUCTS(PRE, pre, pre##_ocb1key, pre##_ocb1aadctx)                        \
+                                                                       \
+typedef struct pre##_ocb1ctx {                                         \
+  /* This is the same as @pre_ocb1aadctx@ above, but the two are       \
+   * logically distinct and shouldn't be muddled up.                   \
+   */                                                                  \
+                                                                       \
+  pre##_ocb1key k;                     /* Processed key material */    \
+  uint32 o[PRE##_BLKSZ/4];             /* Current offset */            \
+  uint32 a[PRE##_BLKSZ/4];             /* Accumulator state */         \
+  octet b[PRE##_BLKSZ];                        /* Input buffer */              \
+  unsigned long i;                     /* Block counter */             \
+  unsigned off;                                /* Offset into buffered data */ \
+} pre##_ocb1ctx;                                                       \
+                                                                       \
+extern const rsvr_policy pre##_ocb1policy;                             \
+                                                                       \
+extern const octet pre##_ocb1noncesz[], pre##_ocb1tagsz[];             \
+                                                                       \
+/* --- @pre_ocb1setkey@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ocb1key *key@ = pointer to key block to fill in    \
+ *             @const void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an OCB1 key block.                          \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb1setkey(pre##_ocb1key */*key*/,                   \
+                            const void */*k*/, size_t /*ksz*/);        \
+                                                                       \
+/* --- @pre_ocb1aadinit@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb1aadctx *aad@ = pointer to AAD context          \
+ *             @const pre_ocb1key *key@ = pointer to key block         \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an OCB1 AAD (`additional authenticated      \
+ *             data') context associated with a given key.  AAD        \
+ *             contexts can be copied and/or reused, saving time if    \
+ *             the AAD for number of messages has a common prefix.     \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around, though        \
+ *             usually there'll at least be another copy in some OCB1  \
+ *             operation context because the AAD on its own isn't much \
+ *             good.                                                   \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb1aadinit(pre##_ocb1aadctx */*aad*/,               \
+                             const pre##_ocb1key */*key*/);            \
+                                                                       \
+/* --- @pre_ocb1aadhash@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb1aadctx *aad@ = pointer to AAD context          \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.                             \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb1aadhash(pre##_ocb1aadctx */*aad*/,               \
+                             const void */*p*/, size_t /*sz*/);        \
+                                                                       \
+/* --- @pre_ocb1aadtag@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @const pre_ocb1aadctx *aad@ = pointer to context block  \
+ *             @uint32 *u@ = where to write the tag                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes processing AAD and produces a tag which can be \
+ *             mixed with an OCB1 checksum.  This function is exposed  \
+ *             for internal reasons and is not expected to be          \
+ *             generally useful.                                       \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb1aadtag(const pre##_ocb1aadctx */*aad*/,          \
+                            uint32 */*t*/);                            \
+                                                                       \
+/* --- @pre_ocb1init@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 context            \
+ *             @const pre_ocb1key *key@ = pointer to key block         \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce length is bad.       \
+ *                                                                     \
+ * Use:                Initialize an OCB1 operation context with a given key.  \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb1init(pre##_ocb1ctx */*ctx*/,                      \
+                         const pre##_ocb1key */*k*/,                   \
+                         const void */*n*/, size_t /*nsz*/);           \
+                                                                       \
+/* --- @pre_ocb1reinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 context            \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce length is bad.       \
+ *                                                                     \
+ * Use:                Reinitialize an OCB1 operation context, changing the    \
+ *             nonce.                                                  \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb1reinit(pre##_ocb1ctx */*ctx*/,                    \
+                           const void */*n*/, size_t /*nsz*/);         \
+                                                                       \
+/* --- @pre_ocb1encrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 operation context  \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB1 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb1encrypt(pre##_ocb1ctx */*ctx*/,                   \
+                            const void */*src*/, size_t /*sz*/,        \
+                            buf */*dst*/);                             \
+                                                                       \
+/* --- @pre_ocb1decrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to OCB1 operation context  \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB1 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb1decrypt(pre##_ocb1ctx */*ctx*/,                   \
+                            const void */*src*/, size_t /*sz*/,        \
+                            buf */*dst*/);                             \
+                                                                       \
+/* --- @pre_ocb1encryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to an OCB1 context         \
+ *             @const pre_ocb1aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an OCB1 encryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB1 delays output, so this will   \
+ *             cause any remaining buffered plaintext to be encrypted  \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb1encryptdone(pre##_ocb1ctx */*ctx*/,               \
+                                const pre##_ocb1aadctx */*aad*/,       \
+                                buf */*dst*/,                          \
+                                void */*tag*/, size_t /*tsz*/);        \
+                                                                       \
+/* --- @pre_ocb1decryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb1ctx *ctx@ = pointer to an OCB1 context         \
+ *             @const pre_ocb1aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an OCB1 decryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB1 delays output, so this will   \
+ *             cause any remaining buffered ciphertext to be decrypted \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb1decryptdone(pre##_ocb1ctx */*ctx*/,               \
+                                const pre##_ocb1aadctx */*aad*/,       \
+                                buf */*dst*/,                          \
+                                const void */*tag*/, size_t /*tsz*/);  \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+extern const gcaead pre##_ocb1;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/ocb3-def.h b/symm/ocb3-def.h
new file mode 100644 (file)
index 0000000..14a22f6
--- /dev/null
@@ -0,0 +1,1006 @@
+/* -*-c-*-
+ *
+ * The OCB3 authenticated encryption mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_OCB3_DEF_H
+#define CATACOMB_OCB3_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_BLKC_H
+#  include "blkc.h"
+#endif
+
+#ifndef CATACOMB_CT_H
+#  include "ct.h"
+#endif
+
+#ifndef CATACOMB_KEYSZ_H
+#  include "keysz.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define OCB3_TSHIFT(PRE) BLKC_GLUE(OCB3_TSHIFT_, BLKC_BITS(PRE))
+#define OCB3_TSHIFT_64 2
+#define OCB3_TSHIFT_96 1
+#define OCB3_TSHIFT_128 1
+#define OCB3_TSHIFT_192 0
+#define OCB3_TSHIFT_256 0
+
+#define OCB3_STRETCHMASK(PRE) BLKC_GLUE(OCB3_STRETCHMASK_, BLKC_BITS(PRE))
+#define OCB3_STRETCHMASK_64 0x1f
+#define OCB3_STRETCHMASK_96 0x3f
+#define OCB3_STRETCHMASK_128 0x3f
+#define OCB3_STRETCHMASK_192 0x7f
+#define OCB3_STRETCHMASK_256 0xff
+
+#define OCB3_STRETCHSHIFT(PRE) BLKC_GLUE(OCB3_STRETCHSHIFT_, BLKC_BITS(PRE))
+#define OCB3_STRETCHSHIFT_64 25
+#define OCB3_STRETCHSHIFT_96 33
+#define OCB3_STRETCHSHIFT_128 8
+#define OCB3_STRETCHSHIFT_192 40
+#define OCB3_STRETCHSHIFT_256 1
+
+/* --- @OCB3_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates an implementation for the OCB3 authenticated-
+ *             encryption mode.
+ */
+
+#define OCB3_DEF(PRE, pre) OCB3_DEFX(PRE, pre, #pre, #pre)
+
+#define OCB3_DEFX(PRE, pre, name, fname)                               \
+                                                                       \
+static const rsvr_policy pre##_ocb3policy =                            \
+  { 0, PRE##_BLKSZ, PRE##_BLKSZ };                                     \
+                                                                       \
+const octet                                                            \
+  pre##_ocb3noncesz[] = { KSZ_RANGE, OCB3_NSZMAX(PRE),                 \
+                         0, OCB3_NSZMAX(PRE), 1 },                     \
+  pre##_ocb3tagsz[] = { KSZ_RANGE, PRE##_BLKSZ, 0, PRE##_BLKSZ, 1 };   \
+                                                                       \
+/* --- @pre_ocb3setkey@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ocb3key *key@ = pointer to OCB3 key block          \
+ *             @ocnst void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes a OCB3 key.  This can be used for           \
+ *             several encryption/or MAC operations.                   \
+ */                                                                    \
+                                                                       \
+void pre##_ocb3setkey(pre##_ocb3key *key, const void *k, size_t ksz)   \
+{                                                                      \
+  unsigned i;                                                          \
+                                                                       \
+  pre##_init(&key->ctx, k, ksz);                                       \
+  BLKC_ZERO(PRE, key->lstar);                                          \
+  pre##_eblk(&key->ctx, key->lstar, key->lstar);                       \
+  BLKC_BLSHIFT(PRE, IRRED, key->ldollar, key->lstar);                  \
+  BLKC_BLSHIFT(PRE, IRRED, key->lmask[0], key->ldollar);               \
+  for (i = 1; i < OCB_NCALC; i++)                                      \
+    BLKC_BLSHIFT(PRE, IRRED, key->lmask[i], key->lmask[i - 1]);                \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3aadinit@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3aadctx *aad@ = pointer to context block        \
+ *             @pre_ocb3key *k@ = key block                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an OCB3 AAD (`additional authenticated      \
+ *             data') context associated witha a given key.            \
+ *             AAD contexts can be copied and/or reused, saving time   \
+ *             if the AAD for a number of messages has a common        \
+ *             prefix.                                                 \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around.               \
+ */                                                                    \
+                                                                       \
+void pre##_ocb3aadinit(pre##_ocb3aadctx *aad, const pre##_ocb3key *k)  \
+{                                                                      \
+  aad->k = *k;                                                         \
+  aad->off = 0; aad->i = 1;                                            \
+  BLKC_ZERO(PRE, aad->a);                                              \
+  BLKC_ZERO(PRE, aad->o);                                              \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3aadhash@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3aadctx *aad@ = pointer to context block        \
+ *             @ocnst void *p@ = pointer to message buffer             \
+ *             @size_t sz@ = size of message buffer                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Hashes some AAD input data.                             \
+ */                                                                    \
+                                                                       \
+void pre##_ocb3aadhash(pre##_ocb3aadctx *aad, const void *p, size_t sz)        \
+{                                                                      \
+  rsvr_state st;                                                       \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *q;                                                      \
+                                                                       \
+  rsvr_setup(&st, &pre##_ocb3policy, aad->b, &aad->off, p, sz);                \
+  RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    OCB_OFFSET(PRE, aad->o, aad->k.lmask, aad->i++);                   \
+    BLKC_LOAD(PRE, t, q); BLKC_XMOVE(PRE, t, aad->o);                  \
+    pre##_eblk(&aad->k.ctx, t, t);                                     \
+    BLKC_XMOVE(PRE, aad->a, t);                                                \
+  }                                                                    \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3augment@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @uint32 *nn@ = where to write the augmented nonce       \
+ *             @const octet *n@ = pointer to input nonce data          \
+ *             @size_t nsz@ = size of input nonce                      \
+ *             @size_t tsz@ = tag length                               \
+ *                                                                     \
+ * Returns:    The nonce shift index.                                  \
+ *                                                                     \
+ * Use:                Constructs the augmented base nonce, mixing in the tag  \
+ *             length appropriately.                                   \
+ */                                                                    \
+                                                                       \
+static unsigned pre##_ocb3augment(uint32 *nn, const octet *n,          \
+                                 size_t nsz, size_t tsz)               \
+{                                                                      \
+  octet b[PRE##_BLKSZ] = { 0 };                                                \
+  uint32 t;                                                            \
+  unsigned nix;                                                                \
+                                                                       \
+  b[0] = 8*(tsz%PRE##_BLKSZ) << OCB3_TSHIFT(PRE);                      \
+  b[PRE##_BLKSZ - nsz - 1] |= 0x01;                                    \
+  memcpy(b + PRE##_BLKSZ - nsz, n, nsz);                               \
+  BLKC_LOAD(PRE, nn, b);                                               \
+  t = BLKC_BWORD(PRE, nn[PRE##_BLKSZ/4 - 1]);                          \
+  nix = t&OCB3_STRETCHMASK(PRE);                                       \
+  t &= ~(uint32)OCB3_STRETCHMASK(PRE);                                 \
+  nn[PRE##_BLKSZ/4 - 1] = BLKC_BWORD(PRE, t);                          \
+  return (nix);                                                                \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3stretch@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Stretches the augmented nonce.                          \
+ */                                                                    \
+                                                                       \
+static void pre##_ocb3stretch(pre##_ocb3ctx *ctx)                      \
+{                                                                      \
+  unsigned nw = OCB3_STRETCHSHIFT(PRE)/32,                             \
+    nl = OCB3_STRETCHSHIFT(PRE)%32, nr = 32 - nl;                      \
+  unsigned i;                                                          \
+  uint32 c = 0, t, u;                                                  \
+                                                                       \
+  pre##_eblk(&ctx->k.ctx, ctx->nbase, ctx->nstretch);                  \
+  for (i = 0; i < PRE##_BLKSZ/4; i++)                                  \
+    ctx->nstretch[i] = BLKC_BWORD(PRE, ctx->nstretch[i]);              \
+  i = PRE##_BLKSZ/4;                                                   \
+  while (i > PRE##_BLKSZ/4 - nw)                                       \
+    { i--; ctx->nstretch[i + PRE##_BLKSZ/4] = ctx->nstretch[i]; }      \
+  while (i--) {                                                                \
+    u = ctx->nstretch[i]; t = ctx->nstretch[i + nw];                   \
+    ctx->nstretch[i + PRE##_BLKSZ/4] = u ^ (t << nl) ^ c;              \
+    if (nr < 32) c = U32(t) >> nr;                                     \
+  }                                                                    \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3shift@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *             @unsigned nix@ = nonce index                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Extracts a chunk out of the OCB3 stretched nonce and    \
+ *             writes it to @ctx->o@.                                  \
+ */                                                                    \
+                                                                       \
+static void pre##_ocb3shift(pre##_ocb3ctx *ctx, unsigned nix)          \
+{                                                                      \
+  unsigned nw = nix/32, nl = nix%32, nr = 32 - nl;                     \
+  uint32 c, t;                                                         \
+  unsigned i;                                                          \
+                                                                       \
+  i = PRE##_BLKSZ/4;                                                   \
+  if (nr < 32) c = U32(ctx->nstretch[PRE##_BLKSZ/4 + nw]) >> nr;       \
+  else c = 0;                                                          \
+  while (i--) {                                                                \
+    t = ctx->nstretch[i + nw];                                         \
+    ctx->o[i] = BLKC_BWORD(PRE, (t << nl) | c);                                \
+    if (nr < 32) c = U32(t) >> nr;                                     \
+  }                                                                    \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3init@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *             @const pre_ocb3key *key@ = pointer to key block         \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *             @size_t tsz@ = tag length                               \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce or tag length is     \
+ *             bad.                                                    \
+ *                                                                     \
+ * Use:                Initialize an OCB3 operation context with a given key.  \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+int pre##_ocb3init(pre##_ocb3ctx *ctx, const pre##_ocb3key *k,         \
+                  const void *n, size_t nsz, size_t tsz)               \
+{                                                                      \
+  unsigned nix;                                                                \
+                                                                       \
+  /* Preflight checking. */                                            \
+  if (nsz > OCB3_NSZMAX(PRE)) return (-1);                             \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+                                                                       \
+  /* Copy over the blockcipher key. */                                 \
+  ctx->k = *k;                                                         \
+                                                                       \
+  /* Sort out the nonce. */                                            \
+  nix = pre##_ocb3augment(ctx->nbase, n, nsz, tsz);                    \
+  ctx->nix = nix; ctx->tsz = tsz;                                      \
+  pre##_ocb3stretch(ctx);                                              \
+  pre##_ocb3shift(ctx, nix);                                           \
+                                                                       \
+  /* Other random things. */                                           \
+  ctx->off = 0;        ctx->i = 1;                                             \
+  BLKC_ZERO(PRE, ctx->a);                                              \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3reinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *             @size_t tsz@ = tag length                               \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce or tag length is     \
+ *             bad.                                                    \
+ *                                                                     \
+ * Use:                Reinitialize an OCB3 operation context, changing the    \
+ *             nonce and/or tag length.                                \
+ */                                                                    \
+                                                                       \
+int pre##_ocb3reinit(pre##_ocb3ctx *ctx,                               \
+                    const void *n, size_t nsz, size_t tsz)             \
+{                                                                      \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  unsigned nix, i;                                                     \
+                                                                       \
+  /* Preflight checking. */                                            \
+  if (nsz > OCB3_NSZMAX(PRE)) return (-1);                             \
+  if (tsz > PRE##_BLKSZ) return (-1);                                  \
+                                                                       \
+  /* Sort out the nonce. */                                            \
+  nix = pre##_ocb3augment(t, n, nsz, tsz);                             \
+  for (i = 0; i < PRE##_BLKSZ/4; i++) {                                        \
+    if (t[i] == ctx->nbase[i]) continue;                               \
+    ctx->nix = nix; ctx->tsz = tsz;                                    \
+    BLKC_MOVE(PRE, ctx->nbase, t); pre##_ocb3stretch(ctx);             \
+    break;                                                             \
+  }                                                                    \
+  pre##_ocb3shift(ctx, nix);                                           \
+                                                                       \
+  /* Other random things. */                                           \
+  ctx->off = 0;        ctx->i = 1;                                             \
+  BLKC_ZERO(PRE, ctx->a);                                              \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3step@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Reinitialize an OCB3 operation context, stepping to     \
+ *             the `next' nonce along.                                 \
+ */                                                                    \
+                                                                       \
+void pre##_ocb3step(pre##_ocb3ctx *ctx)                                        \
+{                                                                      \
+  /* Sort out the nonce. */                                            \
+  if (ctx->nix < OCB3_STRETCHMASK(PRE))                                        \
+    pre##_ocb3shift(ctx, ++ctx->nix);                                  \
+  else {                                                               \
+    ctx->nix = 0;                                                      \
+    BLKC_BADD(PRE, ctx->nbase, OCB3_STRETCHMASK(PRE) + 1);             \
+    pre##_ocb3stretch(ctx);                                            \
+    pre##_ocb3shift(ctx, 0);                                           \
+  }                                                                    \
+                                                                       \
+  /* Other random things. */                                           \
+  ctx->off = 0;        ctx->i = 1;                                             \
+  BLKC_ZERO(PRE, ctx->a);                                              \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3encrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 operation context  \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB3 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+int pre##_ocb3encrypt(pre##_ocb3ctx *ctx,                              \
+                     const void *src, size_t sz, buf *dst)             \
+{                                                                      \
+  rsvr_state st;                                                       \
+  size_t osz;                                                          \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *p;                                                      \
+  octet *q;                                                            \
+                                                                       \
+  /* Figure out what we're going to do. */                             \
+  rsvr_setup(&st, &pre##_ocb3policy, ctx->b, &ctx->off, src, sz);      \
+                                                                       \
+  /* Determine the output size and verify that there is enough         \
+   * space.                                                            \
+   */                                                                  \
+  osz = st.plan.from_rsvr + st.plan.from_input;                                \
+  if (!osz) q = 0;                                                     \
+  else { q = buf_get(dst, osz); if (!q) return (-1); }                 \
+                                                                       \
+  /* Process the input in whole blocks at a time. */                   \
+  RSVR_DO(&st) while ((p = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    OCB_OFFSET(PRE, ctx->o, ctx->k.lmask, ctx->i++);                   \
+    BLKC_LOAD(PRE, t, p); BLKC_XMOVE(PRE, ctx->a, t);                  \
+    BLKC_XMOVE(PRE, t, ctx->o); pre##_eblk(&ctx->k.ctx, t, t);         \
+    BLKC_XSTORE(PRE, q, t, ctx->o); q += PRE##_BLKSZ;                  \
+  }                                                                    \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3decrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 operation context  \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB3 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+int pre##_ocb3decrypt(pre##_ocb3ctx *ctx,                              \
+                     const void *src, size_t sz, buf *dst)             \
+{                                                                      \
+  rsvr_state st;                                                       \
+  size_t osz;                                                          \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *p;                                                      \
+  octet *q;                                                            \
+                                                                       \
+  /* Figure out what we're going to do. */                             \
+  rsvr_setup(&st, &pre##_ocb3policy, ctx->b, &ctx->off, src, sz);      \
+                                                                       \
+  /* Determine the output size and verify that there is enough         \
+   * space.                                                            \
+   */                                                                  \
+  osz = st.plan.from_rsvr + st.plan.from_input;                                \
+  if (!osz) q = 0;                                                     \
+  else { q = buf_get(dst, osz); if (!q) return (-1); }                 \
+                                                                       \
+  /* Process the input in whole blocks at a time. */                   \
+  RSVR_DO(&st) while ((p = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    OCB_OFFSET(PRE, ctx->o, ctx->k.lmask, ctx->i++);                   \
+    BLKC_LOAD(PRE, t, p);                                              \
+    BLKC_XMOVE(PRE, t, ctx->o); pre##_dblk(&ctx->k.ctx, t, t);         \
+    BLKC_XMOVE(PRE, t, ctx->o); BLKC_XMOVE(PRE, ctx->a, t);            \
+    BLKC_STORE(PRE, q, t); q += PRE##_BLKSZ;                           \
+  }                                                                    \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3tag@ --- *                                             \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to an OCB3 context         \
+ *             @const pre_ocb3aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Common end-of-message handling for encryption and       \
+ *             decryption.  The caller is expected to have processed   \
+ *             the last partial block, mixing the padded plaintext     \
+ *             into the checksum and leaving the partial output in     \
+ *             the context's buffer: this function will write the      \
+ *             output to the caller's output buffer.  It will compute  \
+ *             the final full-length tag and leave it in the           \
+ *             context's buffer.                                       \
+ */                                                                    \
+                                                                       \
+static int pre##_ocb3tag(pre##_ocb3ctx *ctx,                           \
+                        const pre##_ocb3aadctx *aad, buf *dst)         \
+{                                                                      \
+  octet *q;                                                            \
+                                                                       \
+  /* Arrange space for the final output (if any). */                   \
+  if (!ctx->off) { q = 0; if (!BOK(dst)) return (-1); }                        \
+  else { q = buf_get(dst, ctx->off); if (!q) return (-1); }            \
+                                                                       \
+  /* Deal with whatever's left in the input buffer, if anything */     \
+  if (ctx->off) memcpy(q, ctx->b, ctx->off);                           \
+                                                                       \
+  /* Wrap up the checksum calculation. */                              \
+  BLKC_XMOVE(PRE, ctx->o, ctx->k.ldollar);                             \
+  BLKC_XMOVE(PRE, ctx->a, ctx->o);                                     \
+  pre##_eblk(&ctx->k.ctx, ctx->a, ctx->a);                             \
+                                                                       \
+  /* Finish off the AAD processing. */                                 \
+  if (aad) {                                                           \
+    if (aad->i) BLKC_XMOVE(PRE, ctx->a, aad->a);                       \
+    if (aad->off) {                                                    \
+      memcpy(ctx->b, aad->b, aad->off);                                        \
+      ctx->b[aad->off] = 0x80;                                         \
+      memset(ctx->b + aad->off + 1, 0, PRE##_BLKSZ - aad->off - 1);    \
+      BLKC_LOAD(PRE, ctx->o, ctx->b);                                  \
+      BLKC_XMOVE(PRE, ctx->o, aad->o);                                 \
+      BLKC_XMOVE(PRE, ctx->o, ctx->k.lstar);                           \
+      pre##_eblk(&ctx->k.ctx, ctx->o, ctx->o);                         \
+      BLKC_XMOVE(PRE, ctx->a, ctx->o);                                 \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  /* Write the final tag. */                                           \
+  BLKC_STORE(PRE, ctx->b, ctx->a);                                     \
+                                                                       \
+  /* Done. */                                                          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3encryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to an OCB3 context         \
+ *             @const pre_ocb3aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an OCB3 encryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB3 delays output, so this will   \
+ *             cause any remaining buffered plaintext to be encrypted  \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+int pre##_ocb3encryptdone(pre##_ocb3ctx *ctx,                          \
+                         const pre##_ocb3aadctx *aad, buf *dst,        \
+                         void *tag, size_t tsz)                        \
+{                                                                      \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ];                             \
+                                                                       \
+  /* Deal with any final partial block. */                             \
+  if (ctx->off) {                                                      \
+    BLKC_XMOVE(PRE, ctx->o, ctx->k.lstar);                             \
+    ctx->b[ctx->off] = 0x80;                                           \
+    memset(ctx->b + ctx->off + 1, 0, PRE##_BLKSZ - ctx->off - 1);      \
+    BLKC_LOAD(PRE, t, ctx->b);                                         \
+    BLKC_XMOVE(PRE, ctx->a, t);                                                \
+    pre##_eblk(&ctx->k.ctx, ctx->o, u);                                        \
+    BLKC_XSTORE(PRE, ctx->b, t, u);                                    \
+  }                                                                    \
+                                                                       \
+  /* Return the tag. */                                                        \
+  assert(tsz == ctx->tsz);                                             \
+  if (pre##_ocb3tag(ctx, aad, dst)) return (-1);                       \
+  memcpy(tag, ctx->b, tsz);                                            \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+/* --- @pre_ocb3decryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to an OCB3 context         \
+ *             @const pre_ocb3aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an OCB3 decryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB3 delays output, so this will   \
+ *             cause any remaining buffered ciphertext to be decrypted \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+int pre##_ocb3decryptdone(pre##_ocb3ctx *ctx,                          \
+                         const pre##_ocb3aadctx *aad, buf *dst,        \
+                         const void *tag, size_t tsz)                  \
+{                                                                      \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ];                             \
+                                                                       \
+  /* Deal with any final partial block. */                             \
+  if (ctx->off) {                                                      \
+    BLKC_XMOVE(PRE, ctx->o, ctx->k.lstar);                             \
+    BLKC_LOAD(PRE, t, ctx->b);                                         \
+    pre##_eblk(&ctx->k.ctx, ctx->o, u);                                        \
+    BLKC_XSTORE(PRE, ctx->b, t, u);                                    \
+    ctx->b[ctx->off] = 0x80;                                           \
+    memset(ctx->b + ctx->off + 1, 0, PRE##_BLKSZ - ctx->off - 1);      \
+    BLKC_XLOAD(PRE, ctx->a, ctx->b);                                   \
+  }                                                                    \
+                                                                       \
+  /* Check the tag. */                                                 \
+  assert(tsz == ctx->tsz);                                             \
+  if (pre##_ocb3tag(ctx, aad, dst)) return (-1);                       \
+  if (ct_memeq(tag, ctx->b, ctx->tsz)) return (+1);                    \
+  else return (0);                                                     \
+}                                                                      \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+typedef struct gactx {                                                 \
+  gaead_aad a;                                                         \
+  pre##_ocb3aadctx aad;                                                        \
+} gactx;                                                               \
+                                                                       \
+static gaead_aad *gadup(const gaead_aad *a)                            \
+  { gactx *aad = S_CREATE(gactx); *aad = *(gactx *)a; return (&aad->a); } \
+                                                                       \
+static void gahash(gaead_aad *a, const void *h, size_t hsz)            \
+  { gactx *aad = (gactx *)a; pre##_ocb3aadhash(&aad->aad, h, hsz); }   \
+                                                                       \
+static void gadestroy(gaead_aad *a)                                    \
+  { gactx *aad = (gactx *)a; BURN(*aad); S_DESTROY(aad); }             \
+                                                                       \
+static const gaead_aadops gaops =                                      \
+  { &pre##_ocb3, gadup, gahash, gadestroy };                           \
+                                                                       \
+static gaead_aad *gaad(const pre##_ocb3key *k)                         \
+{                                                                      \
+  gactx *aad = S_CREATE(gactx);                                                \
+  aad->a.ops = &gaops;                                                 \
+  pre##_ocb3aadinit(&aad->aad, k);                                     \
+  return (&aad->a);                                                    \
+}                                                                      \
+                                                                       \
+typedef struct gectx {                                                 \
+  gaead_enc e;                                                         \
+  pre##_ocb3ctx ctx;                                                   \
+} gectx;                                                               \
+                                                                       \
+static gaead_aad *geaad(gaead_enc *e)                                  \
+  { gectx *enc = (gectx *)e; return (gaad(&enc->ctx.k)); }             \
+                                                                       \
+static int gereinit(gaead_enc *e, const void *n, size_t nsz,           \
+                    size_t hsz, size_t msz, size_t tsz)                \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_ocb3reinit(&enc->ctx, n, nsz, tsz));                   \
+}                                                                      \
+                                                                       \
+static int geenc(gaead_enc *e, const void *m, size_t msz, buf *b)      \
+{                                                                      \
+  gectx *enc = (gectx *)e;                                             \
+  return (pre##_ocb3encrypt(&enc->ctx, m, msz, b));                    \
+}                                                                      \
+                                                                       \
+static int gedone(gaead_enc *e, const gaead_aad *a,                    \
+                 buf *b, void *t, size_t tsz)                          \
+{                                                                      \
+  gectx *enc = (gectx *)e; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_ocb3encryptdone(&enc->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gedestroy(gaead_enc *e)                                    \
+  { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); }             \
+                                                                       \
+static const gaead_encops geops =                                      \
+  { &pre##_ocb3, geaad, gereinit, geenc, gedone, gedestroy };          \
+                                                                       \
+typedef struct gdctx {                                                 \
+  gaead_dec d;                                                         \
+  pre##_ocb3ctx ctx;                                                   \
+} gdctx;                                                               \
+                                                                       \
+static gaead_aad *gdaad(gaead_dec *d)                                  \
+  { gdctx *dec = (gdctx *)d; return (gaad(&dec->ctx.k)); }             \
+                                                                       \
+static int gdreinit(gaead_dec *d, const void *n, size_t nsz,           \
+                    size_t hsz, size_t csz, size_t tsz)                \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_ocb3reinit(&dec->ctx, n, nsz, tsz));                   \
+}                                                                      \
+                                                                       \
+static int gddec(gaead_dec *d, const void *c, size_t csz, buf *b)      \
+{                                                                      \
+  gdctx *dec = (gdctx *)d;                                             \
+  return (pre##_ocb3decrypt(&dec->ctx, c, csz, b));                    \
+}                                                                      \
+                                                                       \
+static int gddone(gaead_dec *d, const gaead_aad *a,                    \
+                 buf *b, const void *t, size_t tsz)                    \
+{                                                                      \
+  gdctx *dec = (gdctx *)d; gactx *aad = (gactx *)a;                    \
+  assert(!a || a->ops == &gaops);                                      \
+  return (pre##_ocb3decryptdone(&dec->ctx, a ? &aad->aad : 0, b, t, tsz)); \
+}                                                                      \
+                                                                       \
+static void gddestroy(gaead_dec *d)                                    \
+  { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); }             \
+                                                                       \
+static const gaead_decops gdops =                                      \
+  { &pre##_ocb3, gdaad, gdreinit, gddec, gddone, gddestroy };          \
+                                                                       \
+typedef struct gkctx {                                                 \
+  gaead_key k;                                                         \
+  pre##_ocb3key key;                                                   \
+} gkctx;                                                               \
+                                                                       \
+static gaead_aad *gkaad(const gaead_key *k)                            \
+  { gkctx *key = (gkctx *)k; return (gaad(&key->key)); }               \
+                                                                       \
+static gaead_enc *gkenc(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t msz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gectx *enc = S_CREATE(gectx);                                                \
+                                                                       \
+  enc->e.ops = &geops;                                                 \
+  if (pre##_ocb3init(&enc->ctx, &key->key, n, nsz, tsz))               \
+    { gedestroy(&enc->e); return (0); }                                        \
+  return (&enc->e);                                                    \
+}                                                                      \
+                                                                       \
+static gaead_dec *gkdec(const gaead_key *k, const void *n, size_t nsz, \
+                       size_t hsz, size_t csz, size_t tsz)             \
+{                                                                      \
+  gkctx *key = (gkctx *)k;                                             \
+  gdctx *dec = S_CREATE(gdctx);                                                \
+                                                                       \
+  dec->d.ops = &gdops;                                                 \
+  if (pre##_ocb3init(&dec->ctx, &key->key, n, nsz, tsz))               \
+    { gddestroy(&dec->d); return (0); }                                        \
+  return (&dec->d);                                                    \
+}                                                                      \
+                                                                       \
+static void gkdestroy(gaead_key *k)                                    \
+  { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); }             \
+                                                                       \
+static const gaead_keyops gkops =                                      \
+  { &pre##_ocb3, gkaad, gkenc, gkdec, gkdestroy };                     \
+                                                                       \
+static gaead_key *gckey(const void *k, size_t ksz)                     \
+{                                                                      \
+  gkctx *key = S_CREATE(gkctx);                                                \
+  key->k.ops = &gkops;                                                 \
+  pre##_ocb3setkey(&key->key, k, ksz);                                 \
+  return (&key->k);                                                    \
+}                                                                      \
+                                                                       \
+const gcaead pre##_ocb3 = {                                            \
+  name "-ocb3",                                                                \
+  pre##_keysz, pre##_ocb3noncesz, pre##_ocb3tagsz,                     \
+  PRE##_BLKSZ, PRE##_BLKSZ - 1, 0, AEADF_PCTSZ,                                \
+  gckey                                                                        \
+};                                                                     \
+                                                                       \
+OCB3_TESTX(PRE, pre, name, fname)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#define OCB3_TEST(PRE, pre) OCB3_TESTX(PRE, pre, #pre, #pre)
+
+/* --- @OCB3_TEST@ --- *
+ *
+ * Arguments:  @PRE, pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Standard test rig for OCB3 functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define OCB3_TESTX(PRE, pre, name, fname)                              \
+                                                                       \
+static int ocb3verify(dstr *v)                                         \
+{                                                                      \
+  pre##_ocb3key key;                                                   \
+  pre##_ocb3aadctx aad;                                                        \
+  pre##_ocb3ctx ctx;                                                   \
+  int ok = 1, win;                                                     \
+  int i;                                                               \
+  octet *p;                                                            \
+  int szs[] = { 1, 7, 192, -1, 0 }, *ip;                               \
+  size_t hsz, msz;                                                     \
+  dstr d = DSTR_INIT, t = DSTR_INIT;                                   \
+  buf b;                                                               \
+                                                                       \
+  dstr_ensure(&d, v[4].len > v[3].len ? v[4].len : v[3].len);          \
+  dstr_ensure(&t, v[5].len); t.len = v[5].len;                         \
+                                                                       \
+  pre##_ocb3setkey(&key, v[0].buf, v[0].len);                          \
+                                                                       \
+  for (ip = szs; *ip; ip++) {                                          \
+                                                                       \
+    pre##_ocb3init(&ctx, &key, (octet *)v[1].buf, v[1].len, v[5].len); \
+                                                                       \
+    i = *ip;                                                           \
+    hsz = v[2].len;                                                    \
+    if (i == -1) i = hsz;                                              \
+    if (i > hsz) continue;                                             \
+    p = (octet *)v[2].buf;                                             \
+    pre##_ocb3aadinit(&aad, &key);                                     \
+    while (hsz) {                                                      \
+      if (i > hsz) i = hsz;                                            \
+      pre##_ocb3aadhash(&aad, p, i);                                   \
+      p += i; hsz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[3].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[3].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_ocb3encrypt(&ctx, p, i, &b)) {                         \
+       puts("!! ocb3encrypt reports failure");                         \
+       goto fail_enc;                                                  \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    if (pre##_ocb3encryptdone(&ctx, &aad, &b, (octet *)t.buf, t.len)) {        \
+      puts("!! ocb3encryptdone reports failure");                      \
+      goto fail_enc;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[4].len ||                                           \
+       memcmp(d.buf, v[4].buf, v[4].len) != 0 ||                       \
+       memcmp(t.buf, v[5].buf, v[5].len) != 0) {                       \
+    fail_enc:                                                          \
+      printf("\nfail encrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tmessage = ", stdout); type_hex.dump(&v[3], stdout);   \
+      fputs("\n\texp ct = ", stdout); type_hex.dump(&v[4], stdout);    \
+      fputs("\n\tcalc ct = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\texp tag = ", stdout); type_hex.dump(&v[5], stdout);   \
+      fputs("\n\tcalc tag = ", stdout); type_hex.dump(&t, stdout);     \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+                                                                       \
+    pre##_ocb3init(&ctx, &key, (octet *)v[1].buf, v[1].len, v[5].len); \
+                                                                       \
+    buf_init(&b, d.buf, d.sz);                                         \
+    i = *ip;                                                           \
+    msz = v[4].len;                                                    \
+    if (i == -1) i = msz;                                              \
+    if (i > msz) continue;                                             \
+    p = (octet *)v[4].buf;                                             \
+    while (msz) {                                                      \
+      if (i > msz) i = msz;                                            \
+      if (pre##_ocb3decrypt(&ctx, p, i, &b)) {                         \
+       puts("!! ocb3decrypt reports failure");                         \
+       win = 0; goto fail_dec;                                         \
+      }                                                                        \
+      p += i; msz -= i;                                                        \
+    }                                                                  \
+                                                                       \
+    win = pre##_ocb3decryptdone(&ctx, &aad, &b,                                \
+                              (octet *)v[5].buf, v[5].len);            \
+    if (win < 0) {                                                     \
+      puts("!! ocb3decryptdone reports failure");                      \
+      goto fail_dec;                                                   \
+    }                                                                  \
+    d.len = BLEN(&b);                                                  \
+                                                                       \
+    if (d.len != v[3].len || !win ||                                   \
+       memcmp(d.buf, v[3].buf, v[3].len) != 0) {                       \
+    fail_dec:                                                          \
+      printf("\nfail decrypt:\n\tstep = %i", *ip);                     \
+      fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);       \
+      fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);     \
+      fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);    \
+      fputs("\n\tciphertext = ", stdout); type_hex.dump(&v[4], stdout);        \
+      fputs("\n\texp pt = ", stdout); type_hex.dump(&v[3], stdout);    \
+      fputs("\n\tcalc pt = ", stdout); type_hex.dump(&d, stdout);      \
+      fputs("\n\ttag = ", stdout); type_hex.dump(&v[5], stdout);       \
+      printf("\n\tverify %s", win ? "ok" : "FAILED");                  \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  dstr_destroy(&d); dstr_destroy(&t);                                  \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static int ocb3mct(dstr *v)                                            \
+{                                                                      \
+  unsigned ksz = *(unsigned long *)v[0].buf, tsz = v[1].len;           \
+  dstr d = DSTR_INIT;                                                  \
+  octet z[128];                                                                \
+  pre##_ocb3key k;                                                     \
+  pre##_ocb3ctx ctx;                                                   \
+  pre##_ocb3aadctx oaad, iaad;                                         \
+  int rc;                                                              \
+  buf b;                                                               \
+  unsigned i;                                                          \
+  int ok = 1;                                                          \
+                                                                       \
+  dstr_ensure(&d, ksz); memset(d.buf, 0, ksz - 4);                     \
+  STORE32_B(d.buf + ksz - 4, 8*tsz);                                   \
+  pre##_ocb3setkey(&k, d.buf, ksz);                                    \
+                                                                       \
+  pre##_ocb3aadinit(&oaad, &k);                                                \
+                                                                       \
+  dstr_ensure(&d, 128 + tsz);                                          \
+  memset(z, 0, 128);                                                   \
+  pre##_ocb3init(&ctx, &k, z, PRE##_BLKSZ - 4, tsz);                   \
+                                                                       \
+  for (i = 0; i < 128; i++) {                                          \
+    pre##_ocb3aadinit(&iaad, &k); pre##_ocb3aadhash(&iaad, z, i);      \
+                                                                       \
+    pre##_ocb3step(&ctx); buf_init(&b, d.buf, i);                      \
+    rc = pre##_ocb3encrypt(&ctx, z, i, &b); if (rc) goto fail;         \
+    rc = pre##_ocb3encryptdone(&ctx, &iaad, &b, d.buf + i, tsz);       \
+    if (rc) goto fail;                                                 \
+    pre##_ocb3aadhash(&oaad, d.buf, i + tsz);                          \
+                                                                       \
+    pre##_ocb3step(&ctx); buf_init(&b, d.buf, i);                      \
+    rc = pre##_ocb3encrypt(&ctx, z, i, &b); if (rc) goto fail;         \
+    rc = pre##_ocb3encryptdone(&ctx, 0, &b, d.buf + i, tsz);           \
+    if (rc) goto fail;                                                 \
+    pre##_ocb3aadhash(&oaad, d.buf, i + tsz);                          \
+                                                                       \
+    pre##_ocb3step(&ctx); buf_init(&b, 0, 0);                          \
+    rc = pre##_ocb3encryptdone(&ctx, &iaad, &b, d.buf, tsz);           \
+    if (rc) goto fail;                                                 \
+    pre##_ocb3aadhash(&oaad, d.buf, tsz);                              \
+  }                                                                    \
+                                                                       \
+  pre##_ocb3step(&ctx); buf_init(&b, 0, 0);                            \
+  rc = pre##_ocb3encryptdone(&ctx, &oaad, &b, d.buf, tsz);             \
+  if (rc) goto fail;                                                   \
+                                                                       \
+  d.len = tsz;                                                         \
+  if (memcmp(d.buf, v[1].buf, tsz) != 0) {                             \
+  fail:                                                                        \
+    printf("\nfail mct: ksz = %u, tsz = %u", ksz, tsz);                        \
+    fputs("\n\texp tag = ", stdout); type_hex.dump(&v[1], stdout);     \
+    fputs("\n\tcalc tag = ", stdout); type_hex.dump(&d, stdout);       \
+    putchar('\n');                                                     \
+    ok = 0;                                                            \
+  }                                                                    \
+                                                                       \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static test_chunk aeaddefs[] = {                                       \
+  { name "-ocb3", ocb3verify,                                          \
+    { &type_hex, &type_hex, &type_hex, &type_hex,                      \
+      &type_hex, &type_hex, 0 } },                                     \
+  { name "-ocb3-mct", ocb3mct,                                         \
+    { &type_ulong, &type_hex, 0 } },                                   \
+  { 0, 0, { 0 } }                                                      \
+};                                                                     \
+                                                                       \
+int main(int argc, char *argv[])                                       \
+{                                                                      \
+  ego(argv[0]);                                                                \
+  test_run(argc, argv, aeaddefs, SRCDIR"/t/" fname);                   \
+  return (0);                                                          \
+}
+
+#else
+#  define OCB3_TESTX(PRE, pre, name, fname)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/ocb3.h b/symm/ocb3.h
new file mode 100644 (file)
index 0000000..ceb2df0
--- /dev/null
@@ -0,0 +1,337 @@
+/* -*-c-*-
+ *
+ * The OCB3 authenticated encryption mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Notes on OCB3 -----------------------------------------------------*
+ *
+ * OCB3 was designed in 2011 by Phillip Rogaway and Ted Krovetz, building ten
+ * years of earlier work by Rogaway, Bellare, and Black, and refining Jutla's
+ * pioneering work on IACBC and IAPM.  OCB3 is an efficient `authenticated
+ * encryption with associated data' (AEAD) scheme which requires only one
+ * blockcipher application per message block.
+ *
+ * The patent situation on these efficient authenticated encryption schemes
+ * is fraught.  IBM hold two patents on Jutla's pioneering work on `IACBC'
+ * and `IAPM' which can apply (a third was filed at least six years too
+ * late), and Virgil Gligor and Pompiliu Donescu hold patents on their `XECB'
+ * and `XCBC' modes; these may or may not apply to OCB.  Rogaway himself
+ * holds US patents on various versions of OCB, but has issued free licences
+ * for free (`open source') software, and for all non-military use.  I think
+ * Catacomb's implementation of OCB falls within the scope of the former
+ * licence.
+ *
+ * OCB3 has optimized for short messages with `similar' nonces, where
+ * `similar' means `all but the low bits in the last byte are equal'; exactly
+ * how many bits depends on the block length in a rather complicated manner.
+ * This implementation supports this optimization through @pre_ocb3reinit@
+ * (which compares the new nonce against the old one to see whether it can
+ * make use of the similarity), and, more directly, through @pre_ocb3step@,
+ * which (effectively) advances the nonce as a big-endian counter.
+ *
+ * OCB3 was originally defined only for 128-bit blockciphers, and extending
+ * it to other sizes is nontrivial, but this has been done by Ted Krovetz in
+ * I-D draft-krovetz-ocb-wideblock-00 (following initial prompting from, err,
+ * me).
+ *
+ * OCB3 is a fairly well-behaved AEAD mode.  It doesn't require
+ * precommentment to the header or message lengths, but does require
+ * precommitment to the tag length.  It permits header data to be processed
+ * independently of any message.  It only accepts nonces the same size as the
+ * underlying blockcipher's block size, and it buffers up to a whole block's
+ * worth of data internally, which somewhat complicates streaming.
+ */
+
+#ifndef CATACOMB_OCB3_H
+#define CATACOMB_OCB3_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+
+#ifndef CATACOMB_GAEAD_H
+#  include "gaead.h"
+#endif
+
+#ifndef CATACOMB_OCB_H
+#  include "ocb.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @OCB3_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates declarations for OCB3 message-authentication mode.
+ */
+
+#define OCB3_NSZMAX(PRE) (PRE##_BLKSZ - (PRE##_BLKSZ <= 16 ? 1 : 2))
+
+#define OCB3_DECL(PRE, pre)                                            \
+                                                                       \
+typedef struct pre##_ocb3key {                                         \
+  pre##_ctx ctx;                       /* Underlying cipher context */ \
+  uint32 lstar[PRE##_BLKSZ/4];         /* Partial-block mask */        \
+  uint32 ldollar[PRE##_BLKSZ/4];       /* Checksum mask */             \
+  uint32 lmask[OCB_NCALC][PRE##_BLKSZ/4]; /* Precalculated masks */    \
+} pre##_ocb3key;                                                       \
+                                                                       \
+typedef struct pre##_ocb3aadctx {                                      \
+  pre##_ocb3key k;                     /* Processed key material */    \
+  uint32 o[PRE##_BLKSZ/4];             /* Current offset */            \
+  uint32 a[PRE##_BLKSZ/4];             /* Accumulator state */         \
+  octet b[PRE##_BLKSZ];                        /* Input buffer */              \
+  unsigned long i;                     /* Block counter */             \
+  unsigned off;                                /* Offset into buffered data */ \
+} pre##_ocb3aadctx;                                                    \
+                                                                       \
+typedef struct pre##_ocb3ctx {                                         \
+  pre##_ocb3key k;                     /* Processed key material */    \
+  unsigned nix, tsz;                   /* Nonce index and tag size */  \
+  uint32 nbase[PRE##_BLKSZ/2];         /* Current base nonce */        \
+  uint32 nstretch[PRE##_BLKSZ/2];      /* Stretched nonce material */  \
+  uint32 o[PRE##_BLKSZ/4];             /* Current offset */            \
+  uint32 a[PRE##_BLKSZ/4];             /* Accumulator state */         \
+  octet b[PRE##_BLKSZ];                        /* Input buffer */              \
+  unsigned long i;                     /* Block counter */             \
+  unsigned off;                                /* Offset into buffered data */ \
+} pre##_ocb3ctx;                                                       \
+                                                                       \
+extern const octet pre##_ocb3noncesz[], pre##_ocb3tagsz[];             \
+                                                                       \
+/* --- @pre_ocb3setkey@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ocb3key *key@ = pointer to key block to fill in    \
+ *             @const void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an OCB3 key block.                          \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb3setkey(pre##_ocb3key */*key*/,                   \
+                            const void */*k*/, size_t /*ksz*/);        \
+                                                                       \
+/* --- @pre_ocb3aadinit@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3aadctx *aad@ = pointer to AAD context          \
+ *             @const pre_ocb3key *key@ = pointer to key block         \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an OCB3 AAD (`additional authenticated      \
+ *             data') context associated with a given key.  AAD        \
+ *             contexts can be copied and/or reused, saving time if    \
+ *             the AAD for number of messages has a common prefix.     \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around, though        \
+ *             usually there'll at least be another copy in some OCB3  \
+ *             operation context because the AAD on its own isn't much \
+ *             good.                                                   \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb3aadinit(pre##_ocb3aadctx */*aad*/,               \
+                             const pre##_ocb3key */*key*/);            \
+                                                                       \
+/* --- @pre_ocb3aadhash@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3aadctx *aad@ = pointer to AAD context          \
+ *             @const void *p@ = pointer to AAD material               \
+ *             @size_t sz@ = length of AAD material                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Feeds AAD into the context.                             \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb3aadhash(pre##_ocb3aadctx */*aad*/,               \
+                             const void */*p*/, size_t /*sz*/);        \
+                                                                       \
+/* --- @pre_ocb3init@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *             @const pre_ocb3key *key@ = pointer to key block         \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *             @size_t tsz@ = tag length                               \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce or tag length is     \
+ *             bad.                                                    \
+ *                                                                     \
+ * Use:                Initialize an OCB3 operation context with a given key.  \
+ *                                                                     \
+ *             The original key needn't be kept around any more.       \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb3init(pre##_ocb3ctx */*ctx*/,                      \
+                         const pre##_ocb3key */*k*/,                   \
+                         const void */*n*/, size_t /*nsz*/,            \
+                         size_t /*tsz*/);                              \
+                                                                       \
+/* --- @pre_ocb3reinit@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *             @const void *n@ = pointer to nonce                      \
+ *             @size_t nsz@ = size of nonce                            \
+ *             @size_t tsz@ = tag length                               \
+ *                                                                     \
+ * Returns:    Zero on success, @-1@ if the nonce or tag length is     \
+ *             bad.                                                    \
+ *                                                                     \
+ * Use:                Reinitialize an OCB3 operation context, changing the    \
+ *             nonce and/or tag length.                                \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb3reinit(pre##_ocb3ctx */*ctx*/,                    \
+                           const void */*n*/, size_t /*nsz*/,          \
+                           size_t /*tsz*/);                            \
+                                                                       \
+/* --- @pre_ocb3step@ --- *                                            \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 context            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Reinitialize an OCB3 operation context, stepping to     \
+ *             the `next' nonce along.                                 \
+ */                                                                    \
+                                                                       \
+extern void pre##_ocb3step(pre##_ocb3ctx */*ctx*/);                    \
+                                                                       \
+/* --- @pre_ocb3encrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 operation context  \
+ *             @const void *src@ = pointer to plaintext message chunk  \
+ *             @size_t sz@ = size of the plaintext                     \
+ *             @buf *dst@ = a buffer to write the ciphertext to        \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Encrypts a chunk of a plaintext message, writing a      \
+ *             chunk of ciphertext to the output buffer and updating   \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB3 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb3encrypt(pre##_ocb3ctx */*ctx*/,                   \
+                            const void */*src*/, size_t /*sz*/,        \
+                            buf */*dst*/);                             \
+                                                                       \
+/* --- @pre_ocb3decrypt@ --- *                                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to OCB3 operation context  \
+ *             @const void *src@ = pointer to ciphertext message chunk \
+ *             @size_t sz@ = size of the ciphertext                    \
+ *             @buf *dst@ = a buffer to write the plaintext to         \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Decrypts a chunk of a ciphertext message, writing a     \
+ *             chunk of plaintext to the output buffer and updating    \
+ *             the operation state.                                    \
+ *                                                                     \
+ *             Note that OCB3 delays output if its input is not a      \
+ *             whole number of blocks.  This means that the output     \
+ *             might be smaller or larger the input by up to the block \
+ *             size.                                                   \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb3decrypt(pre##_ocb3ctx */*ctx*/,                   \
+                            const void */*src*/, size_t /*sz*/,        \
+                            buf */*dst*/);                             \
+                                                                       \
+/* --- @pre_ocb3encryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to an OCB3 context         \
+ *             @const pre_ocb3aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining ciphertext            \
+ *             @void *tag@ = where to write the tag                    \
+ *             @size_t tsz@ = length of tag to store                   \
+ *                                                                     \
+ * Returns:    Zero on success; @-1@ on failure.                       \
+ *                                                                     \
+ * Use:                Completes an OCB3 encryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB3 delays output, so this will   \
+ *             cause any remaining buffered plaintext to be encrypted  \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb3encryptdone(pre##_ocb3ctx */*ctx*/,               \
+                                const pre##_ocb3aadctx */*aad*/,       \
+                                buf */*dst*/,                          \
+                                void */*tag*/, size_t /*tsz*/);        \
+                                                                       \
+/* --- @pre_ocb3decryptdone@ --- *                                     \
+ *                                                                     \
+ * Arguments:  @pre_ocb3ctx *ctx@ = pointer to an OCB3 context         \
+ *             @const pre_ocb3aadctx *aad@ = pointer to AAD context,   \
+ *                     or null                                         \
+ *             @buf *dst@ = buffer for remaining plaintext             \
+ *             @const void *tag@ = tag to verify                       \
+ *             @size_t tsz@ = length of tag                            \
+ *                                                                     \
+ * Returns:    @+1@ for complete success; @0@ if tag verification      \
+ *             failed; @-1@ for other kinds of errors.                 \
+ *                                                                     \
+ * Use:                Completes an OCB3 decryption operation.  The @aad@      \
+ *             pointer may be null if there is no additional           \
+ *             authenticated data.  OCB3 delays output, so this will   \
+ *             cause any remaining buffered ciphertext to be decrypted \
+ *             and written to @dst@.  Anyway, the function will fail   \
+ *             if the output buffer is broken.                         \
+ */                                                                    \
+                                                                       \
+extern int pre##_ocb3decryptdone(pre##_ocb3ctx */*ctx*/,               \
+                                const pre##_ocb3aadctx */*aad*/,       \
+                                buf */*dst*/,                          \
+                                const void */*tag*/, size_t /*tsz*/);  \
+                                                                       \
+/* --- Generic AEAD interface --- */                                   \
+                                                                       \
+extern const gcaead pre##_ocb3;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index e9eb503..e065f08 100644 (file)
 #  include "paranoia.h"
 #endif
 
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
 /*----- Macros ------------------------------------------------------------*/
 
 /* --- @OFB_DEF@ --- *
@@ -87,8 +91,9 @@ void pre##_ofbgetiv(const pre##_ofbctx *ctx, void *iv)                        \
   octet *p = iv;                                                       \
   unsigned off = ctx->off;                                             \
   unsigned rest = PRE##_BLKSZ - off;                                   \
-  memcpy(p, ctx->iv + off, rest);                                      \
-  memcpy(p + rest, ctx->iv, off);                                      \
+                                                                       \
+  memcpy(p, ctx->b + off, rest);                                       \
+  memcpy(p + rest, ctx->b, off);                                       \
 }                                                                      \
                                                                        \
 /* --- @pre_ofbsetiv@ --- *                                            \
@@ -102,10 +107,7 @@ void pre##_ofbgetiv(const pre##_ofbctx *ctx, void *iv)                     \
  */                                                                    \
                                                                        \
 void pre##_ofbsetiv(pre##_ofbctx *ctx, const void *iv)                 \
-{                                                                      \
-  memcpy(ctx->iv, iv, PRE##_BLKSZ);                                    \
-  ctx->off = PRE##_BLKSZ;                                              \
-}                                                                      \
+  { memcpy(ctx->b, iv, PRE##_BLKSZ); ctx->off = 0; }                   \
                                                                        \
 /* --- @pre_ofbbdry@ --- *                                             \
  *                                                                     \
@@ -119,12 +121,13 @@ void pre##_ofbsetiv(pre##_ofbctx *ctx, const void *iv)                    \
                                                                        \
 void pre##_ofbbdry(pre##_ofbctx *ctx)                                  \
 {                                                                      \
-  uint32 niv[PRE##_BLKSZ / 4];                                         \
-  BLKC_LOAD(PRE, niv, ctx->iv);                                                \
-  pre##_eblk(&ctx->ctx, niv, niv);                                     \
-  BLKC_STORE(PRE, ctx->iv, niv);                                       \
-  ctx->off = PRE##_BLKSZ;                                              \
-  BURN(niv);                                                           \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+                                                                       \
+  BLKC_LOAD(PRE, t, ctx->b);                                           \
+  pre##_eblk(&ctx->ctx, t, t);                                         \
+  BLKC_STORE(PRE, ctx->b, t);                                          \
+  ctx->off = 0;                                                                \
+  BURN(t);                                                             \
 }                                                                      \
                                                                        \
 /* --- @pre_ofbsetkey@ --- *                                           \
@@ -138,9 +141,7 @@ void pre##_ofbbdry(pre##_ofbctx *ctx)                                       \
  */                                                                    \
                                                                        \
 void pre##_ofbsetkey(pre##_ofbctx *ctx, const pre##_ctx *k)            \
-{                                                                      \
-  ctx->ctx = *k;                                                       \
-}                                                                      \
+  { ctx->ctx = *k; }                                                   \
                                                                        \
 /* --- @pre_ofbinit@ --- *                                             \
  *                                                                     \
@@ -163,6 +164,7 @@ void pre##_ofbinit(pre##_ofbctx *ctx,                                       \
                     const void *iv)                                    \
 {                                                                      \
   static const octet zero[PRE##_BLKSZ] = { 0 };                                \
+                                                                       \
   pre##_init(&ctx->ctx, key, sz);                                      \
   pre##_ofbsetiv(ctx, iv ? iv : zero);                                 \
 }                                                                      \
@@ -183,81 +185,67 @@ void pre##_ofbinit(pre##_ofbctx *ctx,                                     \
  *             cipher as a random data generator.                      \
  */                                                                    \
                                                                        \
+static const rsvr_policy pre##_ofbpolicy = { 0, PRE##_BLKSZ, PRE##_BLKSZ }; \
+                                                                       \
 void pre##_ofbencrypt(pre##_ofbctx *ctx,                               \
-                       const void *src, void *dest,                    \
-                       size_t sz)                                      \
+                     const void *src, void *dest,                      \
+                     size_t sz)                                        \
 {                                                                      \
-  const octet *s = src;                                                        \
+  rsvr_plan plan;                                                      \
+  const octet *s = src, *p;                                            \
   octet *d = dest;                                                     \
-  unsigned off = ctx->off;                                             \
-                                                                       \
-  /* --- Empty blocks are trivial --- */                               \
-                                                                       \
-  if (!sz)                                                             \
-    return;                                                            \
-                                                                       \
-  /* --- If I can deal with the block from my buffer, do that --- */   \
-                                                                       \
-  if (sz < PRE##_BLKSZ - off)                                          \
-    goto small;                                                                \
-                                                                       \
-  /* --- Finish off what's left in my buffer --- */                    \
-                                                                       \
-  if (!d)                                                              \
-    sz -= PRE##_BLKSZ - off;                                           \
-  else {                                                               \
-    while (off < PRE##_BLKSZ) {                                                \
-      register octet x = s ? *s++ : 0;                                 \
-      *d++ = ctx->iv[off++] ^ x;                                       \
-      sz--;                                                            \
+  uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ/4];                           \
+                                                                       \
+  /* Construct a plan and prepare to follow through. */                        \
+  rsvr_mkplan(&plan, &pre##_ofbpolicy, ctx->off, sz);                  \
+  BLKC_LOAD(PRE, t, ctx->b);                                           \
+                                                                       \
+  /* Initial portion, fulfilled from the buffer.  If the chunk is small        \
+   * enough, then this will be the only portion.  If the buffer is     \
+   * currently empty, then we must prepare it.                         \
+   */                                                                  \
+  if (plan.head) {                                                     \
+    if (!ctx->off) {                                                   \
+      pre##_eblk(&ctx->ctx, t, t);                                     \
+      BLKC_STORE(PRE, ctx->b, t);                                      \
     }                                                                  \
+    p = ctx->b + ctx->off; ctx->off += plan.head;                      \
+    if (!d) /* nothing to do */;                                       \
+    else if (!s) { memcpy(d, p, plan.head); d += plan.head; }          \
+    else while (plan.head--) *d++ = *s++ ^ *p++;                       \
   }                                                                    \
                                                                        \
-  /* --- Main encryption loop --- */                                   \
-                                                                       \
-  {                                                                    \
-    uint32 iv[PRE##_BLKSZ / 4];                                                \
-    BLKC_LOAD(PRE, iv, ctx->iv);                                       \
-                                                                       \
-    for (;;) {                                                         \
-      pre##_eblk(&ctx->ctx, iv, iv);                                   \
-      if (sz < PRE##_BLKSZ)                                            \
-       break;                                                          \
-      if (d) {                                                         \
-       if (!s)                                                         \
-         BLKC_STORE(PRE, d, iv);                                       \
-       else {                                                          \
-         uint32 x[PRE##_BLKSZ / 4];                                    \
-         BLKC_LOAD(PRE, x, s);                                         \
-         BLKC_XSTORE(PRE, d, iv, x);                                   \
-         s += PRE##_BLKSZ;                                             \
-       }                                                               \
-       d += PRE##_BLKSZ;                                               \
-      }                                                                        \
-      sz -= PRE##_BLKSZ;                                               \
-    }                                                                  \
-                                                                       \
-    BLKC_STORE(PRE, ctx->iv, iv);                                      \
-    off = 0;                                                           \
+  /* If the buffer is all used, then reset it ready for next time. */  \
+  ctx->off -= plan.from_rsvr;                                          \
+                                                                       \
+  /* Handle multiple whole blocks. */                                  \
+  if (!d) while (plan.from_input) {                                    \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    plan.from_input -= PRE##_BLKSZ;                                    \
+  } else if (!s) while (plan.from_input) {                             \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ;                           \
+    plan.from_input -= PRE##_BLKSZ;                                    \
+  } else while (plan.from_input) {                                     \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_LOAD(PRE, u, s); s += PRE##_BLKSZ;                            \
+    BLKC_XSTORE(PRE, d, t, u); d += PRE##_BLKSZ;                       \
+    plan.from_input -= PRE##_BLKSZ;                                    \
   }                                                                    \
                                                                        \
-  /* --- Tidying up the tail end --- */                                        \
-                                                                       \
-  if (sz) {                                                            \
-  small:                                                               \
-    if (!d)                                                            \
-      off += sz;                                                       \
-    else do {                                                          \
-      register octet x = s ? *s++ : 0;                                 \
-      *d++ = ctx->iv[off++] ^ x;                                       \
-      sz--;                                                            \
-    } while (sz);                                                      \
+  /* Final portion.  Note that the buffer must be empty if there is a  \
+   * tail, since otherwise the input data would have been part of the  \
+   * head portion instad. */                                           \
+  if (!plan.tail)                                                      \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+  else {                                                               \
+    pre##_eblk(&ctx->ctx, t, t);                                       \
+    BLKC_STORE(PRE, ctx->b, t);                                                \
+    p = ctx->b; ctx->off += plan.tail;                                 \
+    if (!d) /* nothing to do */;                                       \
+    else if (!s) { memcpy(d, p, plan.tail); d += plan.tail; }          \
+    else while (plan.tail--) *d++ = *s++ ^ *p++;                       \
   }                                                                    \
-                                                                       \
-  /* --- Done --- */                                                   \
-                                                                       \
-  ctx->off = off;                                                      \
-  return;                                                              \
 }                                                                      \
                                                                        \
 /* --- Generic cipher interface --- */                                 \
@@ -278,23 +266,13 @@ static gcipher *ginit(const void *k, size_t sz)                           \
 }                                                                      \
                                                                        \
 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)    \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_ofbencrypt(&g->k, s, t, sz);                                   \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_ofbencrypt(&g->k, s, t, sz); }          \
                                                                        \
 static void gdestroy(gcipher *c)                                       \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  BURN(*g);                                                            \
-  S_DESTROY(g);                                                                \
-}                                                                      \
+  { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }                     \
                                                                        \
 static void gsetiv(gcipher *c, const void *iv)                         \
-{                                                                      \
-  gctx *g = (gctx *)c;                                                 \
-  pre##_ofbsetiv(&g->k, iv);                                           \
-}                                                                      \
+  { gctx *g = (gctx *)c; pre##_ofbsetiv(&g->k, iv); }                  \
                                                                        \
 static void gbdry(gcipher *c)                                          \
 {                                                                      \
@@ -320,11 +298,7 @@ typedef struct grctx {                                                     \
 } grctx;                                                               \
                                                                        \
 static void grdestroy(grand *r)                                                \
-{                                                                      \
-  grctx *g = (grctx *)r;                                               \
-  BURN(*g);                                                            \
-  S_DESTROY(g);                                                                \
-}                                                                      \
+  { grctx *g = (grctx *)r; BURN(*g); S_DESTROY(g); }                   \
                                                                        \
 static int grmisc(grand *r, unsigned op, ...)                          \
 {                                                                      \
@@ -403,10 +377,7 @@ static uint32 grword(grand *r)                                             \
 }                                                                      \
                                                                        \
 static void grfill(grand *r, void *p, size_t sz)                       \
-{                                                                      \
-  grctx *g = (grctx *)r;                                               \
-  pre##_ofbencrypt(&g->k, 0, p, sz);                                   \
-}                                                                      \
+  { grctx *g = (grctx *)r; pre##_ofbencrypt(&g->k, 0, p, sz); }                \
                                                                        \
 static const grand_ops grops = {                                       \
   name "-ofb",                                                         \
@@ -442,9 +413,7 @@ OFB_TESTX(PRE, pre, name, name)
 
 #ifdef TEST_RIG
 
-#include <stdio.h>
-
-#include "daftstory.h"
+#include "modes-test.h"
 
 /* --- @OFB_TEST@ --- *
  *
@@ -453,87 +422,26 @@ OFB_TESTX(PRE, pre, name, name)
  * Use:                Standard test rig for OFB functions.
  */
 
-#define OFB_TESTX(PRE, pre, name, fname)                                       \
-                                                                       \
-/* --- Initial plaintext for the test --- */                           \
-                                                                       \
-static const octet text[] = TEXT;                                      \
-                                                                       \
-/* --- Key and IV to use --- */                                                \
+#define OFB_TESTX(PRE, pre, name, fname)                               \
                                                                        \
-static const octet key[] = KEY;                                                \
-static const octet iv[] = IV;                                          \
+static pre##_ctx key;                                                  \
+static pre##_ofbctx ctx;                                               \
                                                                        \
-/* --- Buffers for encryption and decryption output --- */             \
+static void pre##_ofb_test_setup(const octet *k, size_t ksz)           \
+  { pre##_init(&key, k, ksz); pre##_ofbsetkey(&ctx, &key); }           \
                                                                        \
-static octet ct[sizeof(text)];                                         \
-static octet pt[sizeof(text)];                                         \
+static void pre##_ofb_test_reset(const octet *iv)                      \
+  { pre##_ofbsetiv(&ctx, iv); }                                                \
                                                                        \
-static void hexdump(const octet *p, size_t sz, size_t off)             \
-{                                                                      \
-  const octet *q = p + sz;                                             \
-  for (sz = 0; p < q; p++, sz++) {                                     \
-    printf("%02x", *p);                                                        \
-    if ((off + sz + 1) % PRE##_BLKSZ == 0)                             \
-      putchar(':');                                                    \
-  }                                                                    \
-}                                                                      \
+static void pre##_ofb_test_enc(const octet *s, octet *d, size_t sz)    \
+  { pre##_ofbencrypt(&ctx, s, d, sz); }                                        \
                                                                        \
-int main(void)                                                         \
+int main(int argc, char *argv[])                                       \
 {                                                                      \
-  size_t sz = 0, rest;                                                 \
-  pre##_ofbctx ctx;                                                    \
-  int status = 0;                                                      \
-  int done = 0;                                                                \
-  pre##_ctx k;                                                         \
-                                                                       \
-  size_t keysz = PRE##_KEYSZ ?                                         \
-    PRE##_KEYSZ : strlen((const char *)key);                           \
-                                                                       \
-  fputs(name "-ofb: ", stdout);                                                \
-                                                                       \
-  pre##_init(&k, key, keysz);                                          \
-  pre##_ofbsetkey(&ctx, &k);                                           \
-                                                                       \
-  while (sz <= sizeof(text)) {                                         \
-    rest = sizeof(text) - sz;                                          \
-    memcpy(ct, text, sizeof(text));                                    \
-    pre##_ofbsetiv(&ctx, iv);                                          \
-    pre##_ofbencrypt(&ctx, ct, ct, sz);                                        \
-    pre##_ofbencrypt(&ctx, ct + sz, ct + sz, rest);                    \
-    memcpy(pt, ct, sizeof(text));                                      \
-    pre##_ofbsetiv(&ctx, iv);                                          \
-    pre##_ofbencrypt(&ctx, pt, pt, rest);                              \
-    pre##_ofbencrypt(&ctx, pt + rest, pt + rest, sz);                  \
-    if (memcmp(pt, text, sizeof(text)) == 0) {                         \
-      done++;                                                          \
-      if (sizeof(text) < 40 || done % 8 == 0)                          \
-       fputc('.', stdout);                                             \
-      if (done % 480 == 0)                                             \
-       fputs("\n\t", stdout);                                          \
-      fflush(stdout);                                                  \
-    } else {                                                           \
-      printf("\nError (sz = %lu)\n", (unsigned long)sz);               \
-      status = 1;                                                      \
-      printf("\tplaintext      = "); hexdump(text, sz, 0);             \
-       printf(", "); hexdump(text + sz, rest, sz);                     \
-       fputc('\n', stdout);                                            \
-      printf("\tciphertext     = "); hexdump(ct, sz, 0);               \
-       printf(", "); hexdump(ct + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      printf("\trecovered text = "); hexdump(pt, sz, 0);               \
-       printf(", "); hexdump(pt + sz, rest, sz);                       \
-       fputc('\n', stdout);                                            \
-      fputc('\n', stdout);                                             \
-    }                                                                  \
-    if (sz < 63)                                                       \
-      sz++;                                                            \
-    else                                                               \
-      sz += 9;                                                         \
-  }                                                                    \
-                                                                       \
-  fputs(status ? " failed\n" : " ok\n", stdout);                       \
-  return (status);                                                     \
+  return test_encmode(fname "-ofb", PRE##_KEYSZ, PRE##_BLKSZ, 1, 0,    \
+                     pre##_ofb_test_setup, pre##_ofb_test_reset,       \
+                     pre##_ofb_test_enc, pre##_ofb_test_enc,           \
+                     argc, argv);                                      \
 }
 
 #else
index 5eec2ff..6603a4d 100644 (file)
@@ -62,7 +62,7 @@
 typedef struct pre##_ofbctx {                                          \
   pre##_ctx ctx;                       /* Underlying cipher context */ \
   unsigned off;                                /* Current offset in buffer */  \
-  octet iv[PRE##_BLKSZ];               /* Output buffer and IV */      \
+  octet b[PRE##_BLKSZ];                        /* Output buffer and IV */      \
 } pre##_ofbctx;                                                                \
                                                                        \
 /* --- @pre_ofbgetiv@ --- *                                            \
diff --git a/symm/pmac1-def.h b/symm/pmac1-def.h
new file mode 100644 (file)
index 0000000..4b0da04
--- /dev/null
@@ -0,0 +1,371 @@
+/* -*-c-*-
+ *
+ * The PMAC1 message authentication mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef CATACOMB_PMAC1_DEF_H
+#define CATACOMB_PMAC1_DEF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/sub.h>
+
+#ifndef CATACOMB_ARENA_H
+#  include "arena.h"
+#endif
+
+#ifndef CATACOMB_BLKC_H
+#  include "blkc.h"
+#endif
+
+#ifndef CATACOMB_PARANOIA_H
+#  include "paranoia.h"
+#endif
+
+#ifndef CATACOMB_RSVR_H
+#  include "rsvr.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @PMAC1_DEF@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates an implementation for the PMAC1 message-
+ *             authentication mode.
+ */
+
+#define PMAC1_DEF(PRE, pre) PMAC1_DEFX(PRE, pre, #pre, #pre)
+
+#define PMAC1_DEFX(PRE, pre, name, fname)                              \
+                                                                       \
+OCB1_DECL(PRE, pre)                                                    \
+                                                                       \
+const rsvr_policy pre##_ocb1policy =                                   \
+  { RSVRF_FULL, PRE##_BLKSZ, PRE##_BLKSZ };                            \
+                                                                       \
+/* --- @pre_ocb1setkey@, @pre_pmac1setkey@ --- *                       \
+ *                                                                     \
+ * Arguments:  @pre_ocb1key *key@ = pointer to OCB1/PMAC1 key block    \
+ *             @ocnst void *k@ = pointer to key material               \
+ *             @size_t ksz@ = size of key material                     \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes a OCB1/PMAC1 key.  This can be used for     \
+ *             several encryption and/or MAC operations.               \
+ */                                                                    \
+                                                                       \
+void pre##_ocb1setkey(pre##_ocb1key *key, const void *k, size_t ksz)   \
+{                                                                      \
+  unsigned i;                                                          \
+                                                                       \
+  pre##_init(&key->ctx, k, ksz);                                       \
+  BLKC_ZERO(PRE, key->lmask[0]);                                       \
+  pre##_eblk(&key->ctx, key->lmask[0], key->lmask[0]);                 \
+  BLKC_BRSHIFT(PRE, IRRED, key->lxinv, key->lmask[0]);                 \
+  for (i = 1; i < OCB_NCALC; i++)                                      \
+    BLKC_BLSHIFT(PRE, IRRED, key->lmask[i], key->lmask[i - 1]);                \
+}                                                                      \
+void pre##_pmac1setkey(pre##_pmac1key *key, const void *k, size_t ksz) \
+  { pre##_ocb1setkey((pre##_ocb1key *)key, k, ksz); }                  \
+                                                                       \
+/* --- @pre_ocb1aadinit@, @pre_pmac1init --- *                         \
+ *                                                                     \
+ * Arguments:  @pre_ocb1aadctx *aad@ = pointer to context block        \
+ *             @pre_ocb1key *k@ = key block                            \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Initializes an OCB1 AAD (`additional authenticated      \
+ *             data') or PMAC1 context associated witha a given key.   \
+ *             AAD contexts can be copied and/or reused, saving time   \
+ *             if the AAD for a number of messages has a common        \
+ *             prefix.                                                 \
+ *                                                                     \
+ *             The @key@ doesn't need to be kept around.               \
+ */                                                                    \
+                                                                       \
+void pre##_ocb1aadinit(pre##_ocb1aadctx *aad, const pre##_ocb1key *k)  \
+{                                                                      \
+  aad->k = *k;                                                         \
+  aad->off = 0; aad->i = 1;                                            \
+  BLKC_ZERO(PRE, aad->a);                                              \
+  BLKC_ZERO(PRE, aad->o);                                              \
+}                                                                      \
+void pre##_pmac1init(pre##_pmac1ctx *ctx, const pre##_pmac1key *k)     \
+  { pre##_ocb1aadinit((pre##_ocb1aadctx *)ctx, (pre##_ocb1key *)k); }  \
+                                                                       \
+/* --- @pre_ocb1aadhash@, @pre_pmac1hash@ --- *                                \
+ *                                                                     \
+ * Arguments:  @pre_ocb1aadctx *aad@ = pointer to context block        \
+ *             @ocnst void *p@ = pointer to message buffer             \
+ *             @size_t sz@ = size of message buffer                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Hashes some AAD input data.                             \
+ */                                                                    \
+                                                                       \
+void pre##_ocb1aadhash(pre##_ocb1aadctx *aad, const void *p, size_t sz)        \
+{                                                                      \
+  rsvr_state st;                                                       \
+  uint32 t[PRE##_BLKSZ/4];                                             \
+  const octet *q;                                                      \
+                                                                       \
+  rsvr_setup(&st, &pre##_ocb1policy, aad->b, &aad->off, p, sz);                \
+  RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {                \
+    OCB_OFFSET(PRE, aad->o, aad->k.lmask, aad->i++);                   \
+    BLKC_LOAD(PRE, t, q); BLKC_XMOVE(PRE, t, aad->o);                  \
+    pre##_eblk(&aad->k.ctx, t, t);                                     \
+    BLKC_XMOVE(PRE, aad->a, t);                                                \
+  }                                                                    \
+}                                                                      \
+void pre##_pmac1hash(pre##_pmac1ctx *ctx, const void *p, size_t sz)    \
+  { pre##_ocb1aadhash((pre##_ocb1aadctx *)ctx, p, sz); }               \
+                                                                       \
+/* --- @pre_ocb1aadtag@ --- *                                          \
+ *                                                                     \
+ * Arguments:  @const pre_ocb1aadctx *aad@ = pointer to context block  \
+ *             @uint32 *u@ = where to write the tag                    \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes processing AAD and produces a tag which can be \
+ *             mixed with an OCB1 checksum.  This function is exposed  \
+ *             for internal reasons and is not expected to be          \
+ *             generally useful.                                       \
+ */                                                                    \
+                                                                       \
+void pre##_ocb1aadtag(const pre##_ocb1aadctx *aad, uint32 *t)          \
+{                                                                      \
+  octet b[PRE##_BLKSZ];                                                        \
+                                                                       \
+  BLKC_MOVE(PRE, t, aad->a);                                           \
+  if (aad->off == PRE##_BLKSZ) {                                       \
+    BLKC_XLOAD(PRE, t, aad->b);                                                \
+    BLKC_XMOVE(PRE, t, aad->k.lxinv);                                  \
+  } else {                                                             \
+    memcpy(b, aad->b, aad->off); b[aad->off] = 0x80;                   \
+    memset(b + aad->off + 1, 0, PRE##_BLKSZ - aad->off - 1);           \
+    BLKC_XLOAD(PRE, t, b);                                             \
+  }                                                                    \
+  pre##_eblk(&aad->k.ctx, t, t);                                       \
+}                                                                      \
+                                                                       \
+/* --- @pre_pmac1done@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_pmac1ctx *ctx@ = pointer to context block          \
+ *             @void *t@ = where to write the tag                      \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes a MAC operation and produces the tag.  The     \
+ *             context is clobbered and can't be used for anything     \
+ *             useful any more.                                        \
+ */                                                                    \
+                                                                       \
+void pre##_pmac1done(pre##_pmac1ctx *ctx, void *t)                     \
+{                                                                      \
+  uint32 u[PRE##_BLKSZ];                                               \
+  pre##_ocb1aadtag((pre##_ocb1aadctx *)ctx, u); BLKC_STORE(PRE, t, u); \
+}                                                                      \
+                                                                       \
+/* --- Generic MAC interface --- */                                    \
+                                                                       \
+static const gmac_ops gkops;                                           \
+static const ghash_ops gops;                                           \
+                                                                       \
+typedef struct gkctx {                                                 \
+  gmac m;                                                              \
+  pre##_pmac1key k;                                                    \
+} gkctx;                                                               \
+                                                                       \
+typedef struct gctx {                                                  \
+  ghash h;                                                             \
+  pre##_pmac1ctx c;                                                    \
+  octet buf[PRE##_BLKSZ];                                              \
+} gctx;                                                                        \
+                                                                       \
+static ghash *gkinit(gmac *m)                                          \
+{                                                                      \
+  gkctx *gk = (gkctx *)m;                                              \
+  gctx *g = S_CREATE(gctx);                                            \
+  g->h.ops = &gops;                                                    \
+  pre##_pmac1init(&g->c, &gk->k);                                      \
+  return (&g->h);                                                      \
+}                                                                      \
+                                                                       \
+static gmac *gkey(const void *k, size_t sz)                            \
+{                                                                      \
+  gkctx *gk = S_CREATE(gkctx);                                         \
+  gk->m.ops = &gkops;                                                  \
+  pre##_pmac1setkey(&gk->k, k, sz);                                    \
+  return (&gk->m);                                                     \
+}                                                                      \
+                                                                       \
+static void ghhash(ghash *h, const void *p, size_t sz)                 \
+  { gctx *g = (gctx *)h; pre##_pmac1hash(&g->c, p, sz); }              \
+                                                                       \
+static octet *ghdone(ghash *h, void *buf)                              \
+{                                                                      \
+  gctx *g = (gctx *)h;                                                 \
+  if (!buf) buf = g->buf;                                              \
+  pre##_pmac1done(&g->c, buf);                                         \
+  return (buf);                                                                \
+}                                                                      \
+                                                                       \
+static ghash *ghcopy(ghash *h)                                         \
+{                                                                      \
+  gctx *g = (gctx *)h;                                                 \
+  gctx *gg = S_CREATE(gctx);                                           \
+  memcpy(gg, g, sizeof(gctx));                                         \
+  return (&gg->h);                                                     \
+}                                                                      \
+                                                                       \
+static void ghdestroy(ghash *h)                                                \
+  { gctx *g = (gctx *)h; BURN(*g); S_DESTROY(g); }                     \
+                                                                       \
+static void gkdestroy(gmac *m)                                         \
+  { gkctx *gk = (gkctx *)m; BURN(*gk); S_DESTROY(gk); }                        \
+                                                                       \
+static ghash *ghinit(void)                                             \
+{                                                                      \
+  assert(((void)"Attempt to instantiate an unkeyed MAC", 0));          \
+  return (0);                                                          \
+}                                                                      \
+                                                                       \
+const gcmac pre##_pmac1 =                                              \
+  { name "-pmac1", PRE##_BLKSZ, pre##_keysz, gkey };                   \
+static const gmac_ops gkops = { &pre##_pmac1, gkinit, gkdestroy };     \
+static const gchash gch = { name "-pmac1", PRE##_BLKSZ, ghinit };      \
+static const ghash_ops gops =                                          \
+  { &gch, ghhash, ghdone, ghdestroy, ghcopy };                         \
+                                                                       \
+PMAC1_TESTX(PRE, pre, name, fname)
+
+#define PMAC1_TEST(PRE, pre) HMAC_TESTX(PRE, pre, #pre, #pre)
+
+/* --- @PMAC1_TEST@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Standard test rig for PMAC1 functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define PMAC1_TESTX(PRE, pre, name, fname)                             \
+                                                                       \
+static int macverify(dstr *v)                                          \
+{                                                                      \
+  pre##_pmac1ctx cctx;                                                 \
+  pre##_pmac1key ckey;                                                 \
+  int ok = 1;                                                          \
+  int i;                                                               \
+  octet *p;                                                            \
+  int szs[] = { 1, 7, 192, -1, 0 }, *ip;                               \
+  size_t csz;                                                          \
+  dstr d;                                                              \
+                                                                       \
+  dstr_create(&d);                                                     \
+  dstr_ensure(&d, PRE##_BLKSZ);                                                \
+  d.len = PRE##_BLKSZ;                                                 \
+                                                                       \
+  pre##_pmac1setkey(&ckey, v[0].buf, v[0].len);                                \
+                                                                       \
+  for (ip = szs; *ip; ip++) {                                          \
+    i = *ip;                                                           \
+    csz = v[1].len;                                                    \
+    if (i == -1)                                                       \
+      i = csz;                                                         \
+    if (i > csz)                                                       \
+      continue;                                                                \
+    p = (octet *)v[1].buf;                                             \
+    pre##_pmac1init(&cctx, &ckey);                                     \
+    while (csz) {                                                      \
+      if (i > csz)                                                     \
+       i = csz;                                                        \
+      pre##_pmac1hash(&cctx, p, i);                                    \
+      p += i;                                                          \
+      csz -= i;                                                                \
+    }                                                                  \
+    pre##_pmac1done(&cctx, d.buf);                                     \
+    if (memcmp(d.buf, v[2].buf, PRE##_BLKSZ) != 0) {                   \
+      printf("\nfail:\n\tstep = %i\n\tkey = ", *ip);                   \
+      type_hex.dump(&v[0], stdout);                                    \
+      fputs("\n\tinput = ", stdout);                                   \
+      type_hex.dump(&v[1], stdout);                                    \
+      fputs("\n\texpected = ", stdout);                                        \
+      type_hex.dump(&v[2], stdout);                                    \
+      fputs("\n\tcomputed = ", stdout);                                        \
+      type_hex.dump(&d, stdout);                                       \
+      putchar('\n');                                                   \
+      ok = 0;                                                          \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  dstr_destroy(&d);                                                    \
+  return (ok);                                                         \
+}                                                                      \
+                                                                       \
+static test_chunk macdefs[] = {                                                \
+  { name "-pmac1", macverify,                                          \
+    { &type_hex, &type_hex, &type_hex, 0 } },                          \
+  { 0, 0, { 0 } }                                                      \
+};                                                                     \
+                                                                       \
+int main(int argc, char *argv[])                                       \
+{                                                                      \
+  ego(argv[0]);                                                                \
+  test_run(argc, argv, macdefs, SRCDIR"/t/" fname);                    \
+  return (0);                                                          \
+}
+
+#else
+#  define PMAC1_TESTX(PRE, pre, name, fname)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/symm/pmac1.h b/symm/pmac1.h
new file mode 100644 (file)
index 0000000..88827bb
--- /dev/null
@@ -0,0 +1,119 @@
+/* -*-c-*-
+ *
+ * The PMAC1 message authentication mode
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Notes on PMAC1 ----------------------------------------------------*
+ *
+ * PMAC was designed in 2002 by John Black and Phillip Rogaway as a
+ * blockcipher-based MAC which can operate on multiple message blocks in
+ * parallel.  Unfortunately, Rogaway applied for patents on PMAC, and as a
+ * result it saw limited adoption.  Rogaway has since abandoned the patent
+ * applications, and PMAC is free for all uses.
+ *
+ * Confusingly, Rogaway's 2004 paper `Efficient Instantiations of Tweakable
+ * Blockciphers and Refinements to Modes OCB and PMAC' named the new versions
+ * of those modes `OCB1' and `PMAC1'.  The 2011 paper by Krovetz and Rogaway,
+ * `The Software Performance of Authenticated-Encryption Modes' renamed the
+ * original 2001 version of OCB as `OCB1', and the 2004 version `OCB2', and
+ * introduced a new `OCB3', but does not mention PMAC.  (PMAC is used as-is
+ * in the 2001 and 2004 versions of OCB, to process header data; the header
+ * processing in the 2011 version of OCB is not a secure standalone MAC, so
+ * there is no PMAC3.)  I've decided to follow and extend the 2011 naming, so
+ * `PMAC1' refers to the 2002 PMAC; the 2004 version would be `PMAC2'.
+ *
+ * This implementation does not currently attempt to process blocks in
+ * parallel, though this is a possible future improvement.
+ */
+
+#ifndef CATACOMB_PMAC1_H
+#define CATACOMB_PMAC1_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_GMAC_H
+#  include "gmac.h"
+#endif
+
+#ifndef CATACOMB_OCB1_H
+#  include "ocb1.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @PMAC1_DECL@ --- *
+ *
+ * Arguments:  @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use:                Creates declarations for PMAC1 message-authentication mode.
+ *
+ *             Most of these are aliases for OCB1 operations: see
+ *             <catacomb/ocb1.h> for their documentation.
+ */
+
+#define PMAC1_DECL(PRE, pre)                                           \
+                                                                       \
+OCB1_STRUCTS(PRE, pre, pre##_pmac1key, pre##_pmac1ctx)                 \
+                                                                       \
+extern void pre##_pmac1setkey(pre##_pmac1key */*key*/,                 \
+                             const void */*k*/, size_t /*ksz*/);       \
+                                                                       \
+extern void pre##_pmac1init(pre##_pmac1ctx */*ctx*/,                   \
+                           const pre##_pmac1key */*k*/);               \
+                                                                       \
+extern void pre##_pmac1hash(pre##_pmac1ctx */*ctx*/,                   \
+                           const void */*p*/, size_t /*sz*/);          \
+                                                                       \
+/* --- @pre_pmac1done@ --- *                                           \
+ *                                                                     \
+ * Arguments:  @pre_pmac1ctx *ctx@ = pointer to PMAC1 context block    \
+ *             @void *t@ = where to write the tag                      \
+ *                                                                     \
+ * Returns:    ---                                                     \
+ *                                                                     \
+ * Use:                Finishes a MAC operation and produces the tag.          \
+ */                                                                    \
+                                                                       \
+extern void pre##_pmac1done(pre##_pmac1ctx */*ctx*/, void */*t*/);     \
+                                                                       \
+/* --- Generic MAC interface --- */                                    \
+                                                                       \
+extern const gcmac pre##_pmac1;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index d237d4e..c4a88a8 100644 (file)
@@ -33,6 +33,7 @@
 #include <string.h>
 
 #include "poly1305.h"
+#include "rsvr.h"
 
 /*----- Global variables --------------------------------------------------*/
 
@@ -536,28 +537,15 @@ static void update_full(poly1305_ctx *ctx, const octet *p)
   ctx->count++;
 }
 
+static const rsvr_policy pol = { 0, 16, 16 };
+
 void poly1305_hash(poly1305_ctx *ctx, const void *p, size_t sz)
 {
-  const octet *pp = p;
-  size_t n;
-
-  if (ctx->nbuf) {
-    if (sz < 16 - ctx->nbuf) {
-      memcpy(ctx->buf + ctx->nbuf, p, sz);
-      ctx->nbuf += sz;
-      return;
-    }
-    n = 16 - ctx->nbuf;
-    memcpy(ctx->buf + ctx->nbuf, pp, n);
-    update_full(ctx, ctx->buf);
-    pp += n; sz -= n;
-  }
-  while (sz >= 16) {
-    update_full(ctx, pp);
-    pp += 16; sz -= 16;
-  }
-  if (sz) memcpy(ctx->buf, pp, sz);
-  ctx->nbuf = sz;
+  rsvr_state st;
+  const octet *q = p;
+
+  rsvr_setup(&st, &pol, &ctx->buf, &ctx->nbuf, p, sz);
+  RSVR_DO(&st) while ((q = RSVR_NEXT(&st, 16)) != 0) update_full(ctx, q);
 }
 
 /* --- @poly1305_flush@ --- *
index 8a5484c..1df81d9 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
+       .arch   armv8-a
+       .fpu    crypto-neon-fp-armv8
+
        .extern F(abort)
        .extern F(rijndael_rcon)
 
+       .text
+
 ///--------------------------------------------------------------------------
 /// Main code.
 
-       .arch   armv8-a
-       .fpu    crypto-neon-fp-armv8
-
 /// The ARM crypto extension implements a little-endian version of AES
 /// (though the manual doesn't actually spell this out and you have to
 /// experiment), but Catacomb's internal interface presents as big-endian so
index 9f68ae8..98f6173 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
+       .arch   armv8-a+crypto
+
        .extern F(abort)
        .extern F(rijndael_rcon)
 
+       .text
+
 ///--------------------------------------------------------------------------
 /// Main code.
 
-       .arch   armv8-a+crypto
-
 /// The ARM crypto extension implements a little-endian version of AES
 /// (though the manual doesn't actually spell this out and you have to
 /// experiment), but Catacomb's internal interface presents as big-endian so
index 83a49e9..2f65191 100644 (file)
@@ -118,6 +118,7 @@ CPU_DISPATCH(static, EMPTY, void, setup,
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 extern setup__functype rijndael_setup_x86ish_aesni;
+extern setup__functype rijndael_setup_x86ish_aesni_avx;
 #endif
 #if CPUFAM_ARMEL && HAVE_AS_ARMV8_CRYPTO
 extern setup__functype rijndael_setup_arm_crypto;
@@ -129,6 +130,9 @@ extern setup__functype rijndael_setup_arm64_crypto;
 static setup__functype *pick_setup(void)
 {
 #if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(rijndael_setup, rijndael_setup_x86ish_aesni_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX) &&
+                    cpu_feature_p(CPUFEAT_X86_AESNI));
   DISPATCH_PICK_COND(rijndael_setup, rijndael_setup_x86ish_aesni,
                     cpu_feature_p(CPUFEAT_X86_AESNI));
 #endif
index e556aa5..6d9b3b2 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
+       .arch   .aes
+
        .extern F(abort)
        .extern F(rijndael_rcon)
 
+       .text
+
 ///--------------------------------------------------------------------------
 /// Main code.
 
-       .arch   .aes
-       .text
-
 /// The AESNI instructions implement a little-endian version of AES, but
 /// Catacomb's internal interface presents as big-endian so as to work better
 /// with things like GCM.  We therefore maintain the round keys in
 ///--------------------------------------------------------------------------
 /// Key setup.
 
+FUNC(rijndael_setup_x86ish_aesni_avx)
+       vzeroupper                    // avoid penalty on `legacy' XMM access
+  endprologue
+       // and drop through...
+ENDFUNC
+
 FUNC(rijndael_setup_x86ish_aesni)
 
 #define SI WHOLE(si)
@@ -205,16 +212,16 @@ FUNC(rijndael_setup_x86ish_aesni)
        // Fourth word of the cycle, and seven or eight words of key.  Do a
        // byte substitution.
        movd    xmm0, eax
-       pshufd  xmm0, xmm0, SHUF(2, 1, 0, 3)
+       pshufd  xmm0, xmm0, SHUF(3, 0, 1, 2)
        aeskeygenassist xmm1, xmm0, 0
        movd    eax, xmm1
        jmp     2f
 
        // First word of the cycle.  This is the complicated piece.
 1:     movd    xmm0, eax
-       pshufd  xmm0, xmm0, SHUF(0, 3, 2, 1)
+       pshufd  xmm0, xmm0, SHUF(1, 2, 3, 0)
        aeskeygenassist xmm1, xmm0, 0
-       pshufd  xmm1, xmm1, SHUF(2, 1, 0, 3)
+       pshufd  xmm1, xmm1, SHUF(3, 0, 1, 2)
        movd    eax, xmm1
        xor     al, [RCON]
        inc     RCON
@@ -365,6 +372,12 @@ ENDFUNC
 /// Encrypting and decrypting blocks.
 
 .macro encdec  op, aes, koff
+  FUNC(rijndael_\op\()_x86ish_aesni_avx)
+       vzeroupper                      // avoid XMM penalties
+  endprologue
+       // and drop through...
+  ENDFUNC
+
   FUNC(rijndael_\op\()_x86ish_aesni)
 
 #if CPUFAM_X86
index 02cfb76..7db9e01 100644 (file)
@@ -83,6 +83,8 @@ CPU_DISPATCH(EMPTY, EMPTY, void, rijndael_dblk,
 #if CPUFAM_X86 || CPUFAM_AMD64
 extern rijndael_eblk__functype rijndael_eblk_x86ish_aesni;
 extern rijndael_dblk__functype rijndael_dblk_x86ish_aesni;
+extern rijndael_eblk__functype rijndael_eblk_x86ish_aesni_avx;
+extern rijndael_dblk__functype rijndael_dblk_x86ish_aesni_avx;
 #endif
 #if CPUFAM_ARMEL && HAVE_AS_ARMV8_CRYPTO
 extern rijndael_eblk__functype rijndael_eblk_arm_crypto;
@@ -96,6 +98,9 @@ extern rijndael_dblk__functype rijndael_dblk_arm64_crypto;
 static rijndael_eblk__functype *pick_eblk(void)
 {
 #if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(rijndael_eblk, rijndael_eblk_x86ish_aesni_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX) &&
+                    cpu_feature_p(CPUFEAT_X86_AESNI));
   DISPATCH_PICK_COND(rijndael_eblk, rijndael_eblk_x86ish_aesni,
                     cpu_feature_p(CPUFEAT_X86_AESNI));
 #endif
@@ -113,6 +118,9 @@ static rijndael_eblk__functype *pick_eblk(void)
 static rijndael_dblk__functype *pick_dblk(void)
 {
 #if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(rijndael_dblk, rijndael_dblk_x86ish_aesni_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX) &&
+                    cpu_feature_p(CPUFEAT_X86_AESNI));
   DISPATCH_PICK_COND(rijndael_dblk, rijndael_dblk_x86ish_aesni,
                     cpu_feature_p(CPUFEAT_X86_AESNI));
 #endif
index 80ed8f0..3b6beb0 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
-///--------------------------------------------------------------------------
-/// Main.code.
-
        .arch   armv7-a
        .fpu    neon
+
        .text
 
+///--------------------------------------------------------------------------
+/// Main.code.
+
 FUNC(salsa20_core_arm_neon)
 
        // Arguments are in registers.
index 821548e..864c63c 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
-///--------------------------------------------------------------------------
-/// Main.code.
-
        .arch   armv8-a
+
        .text
 
+///--------------------------------------------------------------------------
+/// Main.code.
+
 FUNC(salsa20_core_arm64)
 
        // Arguments are in registers.
index b27f222..e64e733 100644 (file)
  */
 #define SALSA20_PREPBUF(ctx, a) do {                                   \
   int _i;                                                              \
-  for (_i = 0; _i < 16; _i++) STORE32_L((ctx)->buf + 4*_i, (a)[_i]);   \
-  (ctx)->bufi = 0;                                                     \
+  for (_i = 0; _i < 16; _i++) STORE32_L((ctx)->b + 4*_i, (a)[_i]);     \
+  (ctx)->off = 0;                                                      \
 } while (0)
 
 /* Write at most @n@ bytes of buffered output from the context @ctx@ to the
  * @n@ is decreased appropriately.
  */
 #define SALSA20_OUTBUF(ctx, d, s, n) do {                              \
-  size_t _n = (n), _left = SALSA20_OUTSZ - (ctx)->bufi;                        \
-  if (_n > _left) _n = _left;                                          \
-  (n) -= _n;                                                           \
-  if (!(d)) (ctx)->bufi += _n;                                         \
-  else if (s) while (_n--) *(d)++ = (ctx)->buf[(ctx)->bufi++] ^ *(s)++;        \
-  else while (_n--) *(d)++ = (ctx)->buf[(ctx)->bufi++];                        \
+  const octet *_p = (ctx)->b + (ctx)->off;                             \
+  size_t _n = (n);                                                     \
+                                                                       \
+  (ctx)->off += _n;                                                    \
+  if (!(d)) /* nothing to do */;                                       \
+  else if (!(s)) { memcpy((d), _p, _n); (d) += _n; }                   \
+  else while (_n--) *(d)++ = *(s)++ ^ *_p++;                           \
 } while (0)
 
 /*----- Variants and naming -----------------------------------------------*/
diff --git a/symm/salsa20-poly1305.c b/symm/salsa20-poly1305.c
new file mode 100644 (file)
index 0000000..201a083
--- /dev/null
@@ -0,0 +1,85 @@
+/* -*-c-*-
+ *
+ * AEAD schemes based on Salsa20 and Poly1305
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "latinpoly-def.h"
+#include "salsa20.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+LATINPOLY_DEF(salsa20, salsa20, "salsa20")
+LATINPOLY_DEF(salsa2012, salsa20, "salsa20/12")
+LATINPOLY_DEF(salsa208, salsa20, "salsa20/8")
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+#include "latinpoly-test.h"
+
+static int check_salsa20_poly1305(dstr *v)
+  { return latinpoly_test(&salsa20_poly1305, v); }
+static int check_salsa2012_poly1305(dstr *v)
+  { return latinpoly_test(&salsa2012_poly1305, v); }
+static int check_salsa208_poly1305(dstr *v)
+  { return latinpoly_test(&salsa208_poly1305, v); }
+static int check_salsa20_naclbox(dstr *v)
+  { return latinpoly_test(&salsa20_naclbox, v); }
+static int check_salsa2012_naclbox(dstr *v)
+  { return latinpoly_test(&salsa2012_naclbox, v); }
+static int check_salsa208_naclbox(dstr *v)
+  { return latinpoly_test(&salsa208_naclbox, v); }
+
+static const test_chunk tests[] = {
+  { "salsa20-poly1305", check_salsa20_poly1305,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "salsa20/12-poly1305", check_salsa2012_poly1305,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "salsa20/8-poly1305", check_salsa208_poly1305,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "salsa20-naclbox", check_salsa20_naclbox,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "salsa20/12-naclbox", check_salsa2012_naclbox,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { "salsa20/8-nacblox", check_salsa208_naclbox,
+    { &type_hex, &type_hex, &type_hex, &type_hex, &type_hex, &type_hex } },
+  { 0, 0, { 0 } }
+#undef TEST
+};
+
+int main(int argc, char *argv[])
+{
+  ego(argv[0]);
+  test_run(argc, argv, tests, SRCDIR"/t/salsa20");
+  return (0);
+}
+
+#endif
+/*----- That's all, folks -------------------------------------------------*/
index 7d8e2e3..5dc9c17 100644 (file)
 /// MA 02111-1307, USA.
 
 ///--------------------------------------------------------------------------
-/// External definitions.
+/// Preliminaries.
 
 #include "config.h"
 #include "asm-common.h"
 
+       .text
+
 ///--------------------------------------------------------------------------
 /// Main code.
 
-       .arch pentium4
-       .text
+FUNC(salsa20_core_x86ish_avx)
+       .arch   .avx
+       vzeroupper
+  endprologue
+       // drop through...
+ENDFUNC
+
+       .arch   pentium4
 
 FUNC(salsa20_core_x86ish_sse2)
 
@@ -61,7 +69,7 @@ FUNC(salsa20_core_x86ish_sse2)
 #  define SAVE3 [esp + 16]
 
        pushreg ebp
-       setfp   ebp
+       setfp
        sub     esp, 32
        mov     IN, [ebp + 12]
        mov     OUT, [ebp + 16]
@@ -172,7 +180,7 @@ FUNC(salsa20_core_x86ish_sse2)
        // d ^= (c + b) <<< 13
        movdqa  xmm4, xmm2
        paddd   xmm4, xmm1
-        pshufd xmm1, xmm1, SHUF(2, 1, 0, 3)
+        pshufd xmm1, xmm1, SHUF(3, 0, 1, 2)
        movdqa  xmm5, xmm4
        pslld   xmm4, 13
        psrld   xmm5, 19
@@ -181,9 +189,9 @@ FUNC(salsa20_core_x86ish_sse2)
 
        // a ^= (d + c) <<< 18
        movdqa  xmm4, xmm3
-        pshufd xmm3, xmm3, SHUF(0, 3, 2, 1)
+        pshufd xmm3, xmm3, SHUF(1, 2, 3, 0)
        paddd   xmm4, xmm2
-        pshufd xmm2, xmm2, SHUF(1, 0, 3, 2)
+        pshufd xmm2, xmm2, SHUF(2, 3, 0, 1)
        movdqa  xmm5, xmm4
        pslld   xmm4, 18
        psrld   xmm5, 14
@@ -227,7 +235,7 @@ FUNC(salsa20_core_x86ish_sse2)
        // d ^= (c + b) <<< 13
        movdqa  xmm4, xmm2
        paddd   xmm4, xmm3
-        pshufd xmm3, xmm3, SHUF(2, 1, 0, 3)
+        pshufd xmm3, xmm3, SHUF(3, 0, 1, 2)
        movdqa  xmm5, xmm4
        pslld   xmm4, 13
        psrld   xmm5, 19
@@ -236,9 +244,9 @@ FUNC(salsa20_core_x86ish_sse2)
 
        // a ^= (d + c) <<< 18
        movdqa  xmm4, xmm1
-        pshufd xmm1, xmm1, SHUF(0, 3, 2, 1)
+        pshufd xmm1, xmm1, SHUF(1, 2, 3, 0)
        paddd   xmm4, xmm2
-        pshufd xmm2, xmm2, SHUF(1, 0, 3, 2)
+        pshufd xmm2, xmm2, SHUF(2, 3, 0, 1)
        movdqa  xmm5, xmm4
        pslld   xmm4, 18
        psrld   xmm5, 14
@@ -262,9 +270,9 @@ FUNC(salsa20_core_x86ish_sse2)
        // input.  This can be done by juggling values in registers, with the
        // following fancy footwork: some row rotations, a transpose, and
        // some more rotations.
-       pshufd  xmm1, xmm1, SHUF(2, 1, 0, 3)    //  3,  4,  9, 14
-       pshufd  xmm2, xmm2, SHUF(1, 0, 3, 2)    //  2,  7,  8, 13
-       pshufd  xmm3, xmm3, SHUF(0, 3, 2, 1)    //  1,  6, 11, 12
+       pshufd  xmm1, xmm1, SHUF(3, 0, 1, 2)    //  3,  4,  9, 14
+       pshufd  xmm2, xmm2, SHUF(2, 3, 0, 1)    //  2,  7,  8, 13
+       pshufd  xmm3, xmm3, SHUF(1, 2, 3, 0)    //  1,  6, 11, 12
 
        movdqa  xmm4, xmm0
        movdqa  xmm5, xmm3
@@ -280,9 +288,9 @@ FUNC(salsa20_core_x86ish_sse2)
        punpckhdq xmm1, xmm3                    //  5,  6,  7,  4
        punpckhdq xmm2, xmm5                    // 15, 12, 13, 14
 
-       pshufd  xmm1, xmm1, SHUF(2, 1, 0, 3)    //  4,  5,  6,  7
-       pshufd  xmm4, xmm4, SHUF(1, 0, 3, 2)    //  8,  9, 10, 11
-       pshufd  xmm2, xmm2, SHUF(0, 3, 2, 1)    // 12, 13, 14, 15
+       pshufd  xmm1, xmm1, SHUF(3, 0, 1, 2)    //  4,  5,  6,  7
+       pshufd  xmm4, xmm4, SHUF(2, 3, 0, 1)    //  8,  9, 10, 11
+       pshufd  xmm2, xmm2, SHUF(1, 2, 3, 0)    // 12, 13, 14, 15
 
        // Finally we have to write out the result.
        movdqu  [OUT +  0], xmm0
index f424b74..e7c35f4 100644 (file)
@@ -39,6 +39,7 @@
 #include "grand.h"
 #include "keysz.h"
 #include "paranoia.h"
+#include "rsvr.h"
 #include "salsa20.h"
 #include "salsa20-core.h"
 
@@ -72,6 +73,7 @@ static void simple_core(unsigned r, const salsa20_matrix src,
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 extern core__functype salsa20_core_x86ish_sse2;
+extern core__functype salsa20_core_x86ish_avx;
 #endif
 
 #if CPUFAM_ARMEL
@@ -85,6 +87,8 @@ extern core__functype salsa20_core_arm64;
 static core__functype *pick_core(void)
 {
 #if CPUFAM_X86 || CPUFAM_AMD64
+  DISPATCH_PICK_COND(salsa20_core, salsa20_core_x86ish_avx,
+                    cpu_feature_p(CPUFEAT_X86_AVX));
   DISPATCH_PICK_COND(salsa20_core, salsa20_core_x86ish_sse2,
                     cpu_feature_p(CPUFEAT_X86_SSE2));
 #endif
@@ -159,6 +163,8 @@ static void populate(salsa20_matrix a, const void *key, size_t ksz)
 
 /*----- Salsa20 implementation --------------------------------------------*/
 
+static const octet zerononce[XSALSA20_NONCESZ];
+
 /* --- @salsa20_init@ --- *
  *
  * Arguments:  @salsa20_ctx *ctx@ = context to fill in
@@ -174,8 +180,6 @@ static void populate(salsa20_matrix a, const void *key, size_t ksz)
 void salsa20_init(salsa20_ctx *ctx, const void *key, size_t ksz,
                  const void *nonce)
 {
-  static const octet zerononce[SALSA20_NONCESZ];
-
   populate(ctx->a, key, ksz);
   salsa20_setnonce(ctx, nonce ? nonce : zerononce);
 }
@@ -231,7 +235,7 @@ void salsa20_seek(salsa20_ctx *ctx, unsigned long i)
 void salsa20_seeku64(salsa20_ctx *ctx, kludge64 i)
 {
   ctx->a[8] = LO64(i); ctx->a[5] = HI64(i);
-  ctx->bufi = SALSA20_OUTSZ;
+  ctx->off = 0;
 }
 
 void salsa20_seek_ietf(salsa20_ctx *ctx, uint32 i)
@@ -271,6 +275,8 @@ uint32 salsa20_tell_ietf(salsa20_ctx *ctx)
  *             to @dest@.
  */
 
+static const rsvr_policy policy = { 0, SALSA20_OUTSZ, SALSA20_OUTSZ };
+
 #define SALSA20_ENCRYPT(r, ctx, src, dest, sz)                         \
   SALSA20_DECOR(salsa20, r, _encrypt)(ctx, src, dest, sz)
 #define DEFENCRYPT(r)                                                  \
@@ -280,41 +286,40 @@ uint32 salsa20_tell_ietf(salsa20_ctx *ctx)
     salsa20_matrix b;                                                  \
     const octet *s = src;                                              \
     octet *d = dest;                                                   \
-    size_t n;                                                          \
+    rsvr_plan plan;                                                    \
     kludge64 pos, delta;                                               \
                                                                        \
-    SALSA20_OUTBUF(ctx, d, s, sz);                                     \
-    if (!sz) return;                                                   \
-                                                                       \
-    if (!dest) {                                                       \
-      n = sz/SALSA20_OUTSZ;                                            \
-      pos = salsa20_tellu64(ctx);                                      \
-      ASSIGN64(delta, n);                                              \
-      ADD64(pos, pos, delta);                                          \
-      salsa20_seeku64(ctx, pos);                                       \
-      sz = sz%SALSA20_OUTSZ;                                           \
-    } else if (!src) {                                                 \
-      while (sz >= SALSA20_OUTSZ) {                                    \
-       core(r, ctx->a, b);                                             \
-       SALSA20_STEP(ctx->a);                                           \
-       SALSA20_GENFULL(b, d);                                          \
-       sz -= SALSA20_OUTSZ;                                            \
+    rsvr_mkplan(&plan, &policy, ctx->off, sz);                         \
+                                                                       \
+    if (plan.head) {                                                   \
+      if (!ctx->off) {                                                 \
+       core(r, ctx->a, b); SALSA20_STEP(ctx->a);                       \
+       SALSA20_PREPBUF(ctx, b);                                        \
       }                                                                        \
-    } else {                                                           \
-      while (sz >= SALSA20_OUTSZ) {                                    \
-       core(r, ctx->a, b);                                             \
-       SALSA20_STEP(ctx->a);                                           \
-       SALSA20_MIXFULL(b, d, s);                                       \
-       sz -= SALSA20_OUTSZ;                                            \
+      SALSA20_OUTBUF(ctx, d, s, plan.head);                            \
+    }                                                                  \
+                                                                       \
+    ctx->off -= plan.from_rsvr;                                                \
+                                                                       \
+    if (!d) {                                                          \
+      if (plan.from_input) {                                           \
+       pos = salsa20_tellu64(ctx);                                     \
+       ASSIGN64(delta, plan.from_input/SALSA20_OUTSZ);                 \
+       ADD64(pos, pos, delta);                                         \
+       salsa20_seeku64(ctx, pos);                                      \
       }                                                                        \
+    } else if (!s) while (plan.from_input) {                           \
+      core(r, ctx->a, b); SALSA20_STEP(ctx->a);                                \
+      SALSA20_GENFULL(b, d); plan.from_input -= SALSA20_OUTSZ;         \
+    } else while (plan.from_input) {                                   \
+      core(r, ctx->a, b); SALSA20_STEP(ctx->a);                                \
+      SALSA20_MIXFULL(b, d, s); plan.from_input -= SALSA20_OUTSZ;      \
     }                                                                  \
                                                                        \
-    if (sz) {                                                          \
-      core(r, ctx->a, b);                                              \
-      SALSA20_STEP(ctx->a);                                            \
+    if (plan.tail) {                                                   \
+      core(r, ctx->a, b); SALSA20_STEP(ctx->a);                                \
       SALSA20_PREPBUF(ctx, b);                                         \
-      SALSA20_OUTBUF(ctx, d, s, sz);                                   \
-      assert(!sz);                                                     \
+      SALSA20_OUTBUF(ctx, d, s, plan.tail);                            \
     }                                                                  \
   }
 SALSA20_VARS(DEFENCRYPT)
@@ -419,8 +424,6 @@ SALSA20_VARS(DEFHSALSA20)
   void XSALSA20_INIT(r, XSALSA20_CTX(r) *ctx,                          \
                        const void *key, size_t ksz, const void *nonce) \
   {                                                                    \
-    static const octet zerononce[XSALSA20_NONCESZ];                    \
-                                                                       \
     populate(ctx->k, key, ksz);                                                \
     ctx->s.a[ 0] = SALSA20_A256;                                       \
     ctx->s.a[ 1] = SALSA20_B256;                                       \
index 317a34c..7f3059e 100644 (file)
@@ -64,8 +64,8 @@ typedef uint32 salsa20_matrix[16];
 
 typedef struct salsa20_ctx {
   salsa20_matrix a;
-  octet buf[SALSA20_OUTSZ];
-  size_t bufi;
+  octet b[SALSA20_OUTSZ];
+  unsigned off;
 } salsa20_ctx;
 
 #define XSALSA20_DEFCTX(name)                                          \
index 0ba56c0..a4a0a3f 100644 (file)
@@ -62,35 +62,37 @@ static void sealgamma(uint32 *p, size_t sz, const void *k, unsigned i)
 {
   uint32 buf[80] = { 0 };
   const octet *kk = k;
-  uint32 aa = LOAD32(kk);
-  uint32 bb = LOAD32(kk + 4);
-  uint32 cc = LOAD32(kk + 8);
-  uint32 dd = LOAD32(kk + 12);
-  uint32 ee = LOAD32(kk + 16);
+  uint32 a, aa = LOAD32(kk);
+  uint32 b, bb = LOAD32(kk + 4);
+  uint32 c, cc = LOAD32(kk + 8);
+  uint32 d, dd = LOAD32(kk + 12);
+  uint32 e, ee = LOAD32(kk + 16);
+
+  unsigned skip = i%5;
+  uint32 x;
+  int j;
 
-  unsigned skip = i % 5;
   i /= 5;
 
   /* --- While there's hashing to do, do hashing --- */
 
   while (sz) {
-    uint32 a = aa, b = bb, c = cc, d = dd, e = ee;
-    int j;
+    a = aa, b = bb, c = cc, d = dd, e = ee;
 
     /* --- Initialize and expand the buffer --- */
 
     buf[0] = i++;
 
     for (j = 16; j < 80; j++) {
-      uint32 x = buf[j - 3] ^ buf[j - 8] ^ buf[j - 14] ^ buf[j - 16];
+      x = buf[j - 3] ^ buf[j - 8] ^ buf[j - 14] ^ buf[j - 16];
       buf[j] = ROL32(x, 1);
     }
 
     /* --- Definitions for round functions --- */
 
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define F(x, y, z) (((x)&(y)) | (~(x)&(z)))
 #define G(x, y, z) ((x) ^ (y) ^ (z))
-#define H(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) (((x)&(y)) | ((x)&(z)) | ((y)&(z)))
 
 #define T(v, w, x, y, z, i, f, k) do {                                 \
   uint32 _x;                                                           \
@@ -109,14 +111,10 @@ static void sealgamma(uint32 *p, size_t sz, const void *k, unsigned i)
      * Since this isn't doing bulk hashing, do it the easy way.
      */
 
-    for (j = 0; j < 20; j++)
-      FF(a, b, c, d, e, j);
-    for (j = 20; j < 40; j++)
-      GG(a, b, c, d, e, j);
-    for (j = 40; j < 60; j++)
-      HH(a, b, c, d, e, j);
-    for (j = 60; j < 80; j++)
-      II(a, b, c, d, e, j);
+    for (j =  0; j < 20; j++) FF(a, b, c, d, e, j);
+    for (j = 20; j < 40; j++) GG(a, b, c, d, e, j);
+    for (j = 40; j < 60; j++) HH(a, b, c, d, e, j);
+    for (j = 60; j < 80; j++) II(a, b, c, d, e, j);
 
     /* --- Do the chaining at the end --- */
 
@@ -125,17 +123,12 @@ static void sealgamma(uint32 *p, size_t sz, const void *k, unsigned i)
     /* --- Write to the output buffer --- */
 
     switch (skip) {
-      case 0:
-       if (sz) { *p++ = a; sz--; }
-      case 1:
-       if (sz) { *p++ = b; sz--; }
-      case 2:
-       if (sz) { *p++ = c; sz--; }
-      case 3:
-       if (sz) { *p++ = d; sz--; }
-      case 4:
-       if (sz) { *p++ = e; sz--; }
-       skip = 0;
+      case 0: if (sz) { *p++ = a; sz--; }
+      case 1: if (sz) { *p++ = b; sz--; }
+      case 2: if (sz) { *p++ = c; sz--; }
+      case 3: if (sz) { *p++ = d; sz--; }
+      case 4: if (sz) { *p++ = e; sz--; }
+      skip = 0;
     }
   }
 }
@@ -155,16 +148,12 @@ static void sealgamma(uint32 *p, size_t sz, const void *k, unsigned i)
 
 void seal_initkey(seal_key *k, const void *buf, size_t sz)
 {
+  sha_ctx h;
+
   /* --- Hash the key if it's the wrong size --- */
 
-  if (sz == SHA_HASHSZ)
-    memcpy(k->k, buf, sizeof(k->k));
-  else {
-    sha_ctx c;
-    sha_init(&c);
-    sha_hash(&c, buf, sz);
-    sha_done(&c, k->k);
-  }
+  if (sz == SHA_HASHSZ) memcpy(k->k, buf, sizeof(k->k));
+  else { sha_init(&h); sha_hash(&h, buf, sz); sha_done(&h, k->k); }
 
   /* --- Expand the key to fit the various tables --- */
 
@@ -208,14 +197,14 @@ static void seal_reset(seal_ctx *c)
 
   /* --- Ensure that everything is sufficiently diffused --- */
 
-  p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
-  p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
-  p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
-  p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
-  p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
-  p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
-  p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
-  p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
+  p = A&0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
+  p = B&0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
+  p = C&0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
+  p = D&0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
+  p = A&0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
+  p = B&0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
+  p = C&0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
+  p = D&0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
 
   /* --- Write out some context --- */
 
@@ -223,10 +212,10 @@ static void seal_reset(seal_ctx *c)
 
   /* --- Diffuse some more --- */
 
-  p = A & 0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
-  p = B & 0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
-  p = C & 0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
-  p = D & 0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
+  p = A&0x7fc; B += k->t[p >> 2]; A = ROR32(A, 9);
+  p = B&0x7fc; C += k->t[p >> 2]; B = ROR32(B, 9);
+  p = C&0x7fc; D += k->t[p >> 2]; C = ROR32(C, 9);
+  p = D&0x7fc; A += k->t[p >> 2]; D = ROR32(D, 9);
 
   /* --- Write out the magic numbers --- */
 
@@ -253,7 +242,7 @@ void seal_initctx(seal_ctx *c, seal_key *k, uint32 n)
   c->l = 0;
   c->r = k->r;
   c->ri = 0x2000 + SEAL_R;
-  c->qsz = 0;
+  c->off = 16;
   seal_reset(c);
 }
 
@@ -274,34 +263,32 @@ void seal_initctx(seal_ctx *c, seal_key *k, uint32 n)
 
 void seal_encrypt(seal_ctx *c, const void *src, void *dest, size_t sz)
 {
+  seal_key *k = c->k;
   const octet *s = src;
-  octet *d = dest;
+  octet *d = dest, *p;
+  uint32 A = c->a, B = c->b, C = c->c, D = c->d;
+  uint32 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
+  uint32 aa, bb, cc, dd;
+  unsigned i, j;
+  unsigned P, Q;
 
   /* --- Expect a big dollop of bytes --- */
 
-  if (sz > c->qsz) {
-    seal_key *k = c->k;
-    uint32 A = c->a, B = c->b, C = c->c, D = c->d;
-    uint32 n1 = c->n1, n2 = c->n2, n3 = c->n3, n4 = c->n4;
-    uint32 aa, bb, cc, dd;
-    unsigned j = c->i;
-
-    /* --- Empty the queue first --- */
-
-    if (c->qsz) {
-      if (d) {
-       unsigned i;
-       octet *p = c->q + sizeof(c->q) - c->qsz;
-       for (i = 0; i < c->qsz; i++)
-         *d++ = (s ? *s++ ^ *p++ : *p++);
-      }
-      sz -= c->qsz;
+  if (sz > 16 - c->off) {
+    j = c->i;
+
+    /* --- Drain the buffer first --- */
+
+    if (c->off < 16) {
+      p = c->buf + c->off; sz -= 16 - c->off;
+      if (!d) /* nothing to do* */;
+      else if (!s) memcpy(d, p, 16 - c->off);
+      else for (i = c->off; i < 16; i++) *d++ = *s++ ^ *p++;
     }
 
     /* --- Main sequence --- */
 
     for (;;) {
-      unsigned P, Q;
 
       /* --- Reset if we've run out of steam on this iteration --- */
 
@@ -314,74 +301,63 @@ void seal_encrypt(seal_ctx *c, const void *src, void *dest, size_t sz)
 
       /* --- Make some new numbers --- */
 
-      P = A & 0x7fc; B += k->t[P >> 2]; A = ROR32(A, 9); B ^= A;
-      Q = B & 0x7fc; C ^= k->t[Q >> 2]; B = ROR32(B, 9); C += B;
-      P = (P + C) & 0x7fc; D += k->t[P >> 2]; C = ROR32(C, 9); D ^= C;
-      Q = (Q + D) & 0x7fc; A ^= k->t[Q >> 2]; D = ROR32(D, 9); A += D;
-      P = (P + A) & 0x7fc; B ^= k->t[P >> 2]; A = ROR32(A, 9);
-      Q = (Q + B) & 0x7fc; C += k->t[Q >> 2]; B = ROR32(B, 9);
-      P = (P + C) & 0x7fc; D ^= k->t[P >> 2]; C = ROR32(C, 9);
-      Q = (Q + D) & 0x7fc; A += k->t[Q >> 2]; D = ROR32(D, 9);
+      P =       A&0x7fc; B += k->t[P >> 2]; A = ROR32(A, 9); B ^= A;
+      Q =       B&0x7fc; C ^= k->t[Q >> 2]; B = ROR32(B, 9); C += B;
+      P = (P + C)&0x7fc; D += k->t[P >> 2]; C = ROR32(C, 9); D ^= C;
+      Q = (Q + D)&0x7fc; A ^= k->t[Q >> 2]; D = ROR32(D, 9); A += D;
+      P = (P + A)&0x7fc; B ^= k->t[P >> 2]; A = ROR32(A, 9);
+      Q = (Q + B)&0x7fc; C += k->t[Q >> 2]; B = ROR32(B, 9);
+      P = (P + C)&0x7fc; D ^= k->t[P >> 2]; C = ROR32(C, 9);
+      Q = (Q + D)&0x7fc; A += k->t[Q >> 2]; D = ROR32(D, 9);
 
       /* --- Remember the output and set up the next round --- */
 
-      aa = B + k->s[j + 0];
-      bb = C ^ k->s[j + 1];
-      cc = D + k->s[j + 2];
-      dd = A ^ k->s[j + 3];
+      aa = B + k->s[j + 0]; bb = C ^ k->s[j + 1];
+      cc = D + k->s[j + 2]; dd = A ^ k->s[j + 3];
       j += 4;
 
-      if (j & 4)
-       A += n1, B += n2, C ^= n1, D ^= n2;
-      else
-       A += n3, B += n4, C ^= n3, D ^= n4;
+      if (j&4) { A += n1; B += n2; C ^= n1; D ^= n2; }
+      else     { A += n3; B += n4; C ^= n3; D ^= n4; }
 
       /* --- Bail out here if we need to do buffering --- */
 
-      if (sz < 16)
-       break;
+      if (sz < 16) break;
 
       /* --- Write the next 16 bytes --- */
 
-      if (d) {
+      if (!d) /* nothing to do */;
+      else {
        if (s) {
-         aa ^= LOAD32_L(s + 0);
-         bb ^= LOAD32_L(s + 4);
-         cc ^= LOAD32_L(s + 8);
-         dd ^= LOAD32_L(s + 12);
+         aa ^= LOAD32_L(s +  0); bb ^= LOAD32_L(s +  4);
+         cc ^= LOAD32_L(s +  8); dd ^= LOAD32_L(s + 12);
          s += 16;
        }
-       STORE32_L(d + 0, aa);
-       STORE32_L(d + 4, bb);
-       STORE32_L(d + 8, cc);
-       STORE32_L(d + 12, dd);
+       STORE32_L(d +  0, aa); STORE32_L(d +  4, bb);
+       STORE32_L(d +  8, cc); STORE32_L(d + 12, dd);
        d += 16;
       }
       sz -= 16;
     }
 
-    /* --- Write the new queue --- */
+    /* --- Write the new buffer --- */
 
-    STORE32_L(c->q + 0, aa);
-    STORE32_L(c->q + 4, bb);
-    STORE32_L(c->q + 8, cc);
-    STORE32_L(c->q + 12, dd);
-    c->qsz = 16;
+    STORE32_L(c->buf +  0, aa);
+    STORE32_L(c->buf +  4, bb);
+    STORE32_L(c->buf +  8, cc);
+    STORE32_L(c->buf + 12, dd);
+    c->off = 0;
 
     c->a = A; c->b = B; c->c = C; c->d = D;
     c->i = j;
   }
 
-  /* --- Deal with the rest from the queue --- */
+  /* --- Deal with the rest from the buffer --- */
 
   if (sz) {
-    unsigned i;
-    octet *p = c->q + sizeof(c->q) - c->qsz;
-    if (d) {
-      for (i = 0; i < sz; i++)
-       *d++ = (s ? *s++ ^ *p++ : *p++);
-    }
-    c->qsz -= sz;
+    p = c->buf + c->off; c->off += sz;
+    if (!d) /* nothing to do* */;
+    else if (!s) memcpy(d, p, sz);
+    else for (i = 0; i < sz; i++) *d++ = *s++ ^ *p++;
   }
 }
 
@@ -405,10 +381,7 @@ static gcipher *ginit(const void *k, size_t sz)
 }
 
 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)
-{
-  gctx *g = (gctx *)c;
-  seal_encrypt(&g->cc, s, t, sz);
-}
+  { gctx *g = (gctx *)c; seal_encrypt(&g->cc, s, t, sz); }
 
 static void gsetiv(gcipher *c, const void *iv)
 {
@@ -418,11 +391,7 @@ static void gsetiv(gcipher *c, const void *iv)
 }
 
 static void gdestroy(gcipher *c)
-{
-  gctx *g = (gctx *)c;
-  BURN(*g);
-  S_DESTROY(g);
-}
+  { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); }
 
 static const gcipher_ops gops = {
   &seal,
@@ -443,11 +412,7 @@ typedef struct grctx {
 } grctx;
 
 static void grdestroy(grand *r)
-{
-  grctx *g = (grctx *)r;
-  BURN(*g);
-  S_DESTROY(g);
-}
+  { grctx *g = (grctx *)r; BURN(*g); S_DESTROY(g); }
 
 static int grmisc(grand *r, unsigned op, ...)
 {
@@ -520,10 +485,7 @@ static uint32 grword(grand *r)
 }
 
 static void grfill(grand *r, void *p, size_t sz)
-{
-  grctx *g = (grctx *)r;
-  seal_encrypt(&g->cc, 0, p, sz);
-}
+  { grctx *g = (grctx *)r; seal_encrypt(&g->cc, 0, p, sz); }
 
 static const grand_ops grops = {
   "seal",
index 875994e..adb17ab 100644 (file)
@@ -76,8 +76,8 @@ typedef struct seal_ctx {
   uint32 a, b, c, d;                   /* Current chaining variables */
   uint32 n1, n2, n3, n4;               /* Increments for the variables */
   unsigned i;                          /* Index into current iteration */
-  octet q[16];                         /* Output buffer */
-  unsigned qsz;                                /* Number of bytes in the buffer */
+  octet buf[16];                       /* Output buffer */
+  unsigned off;                                /* Offset into the buffer */
   uint32 rbuf[SEAL_R];                 /* Buffer for later magic */
 } seal_ctx;
 
index c29de5b..686b574 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef CATACOMB_@{name:u:c}_H
 #define CATACOMB_@{name:u:c}_H
 
-#ifndef CATACOMB_@{base:u}_H
+#ifndef CATACOMB_@{base:u:c}_H
 #  include "@base.h"
 #endif
 
index 449f967..a49688c 100644 (file)
@@ -117,3 +117,933 @@ blowfish {
   f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344556677
        fedcba9876543210        05044b62fa52d080;
 }
+
+blowfish-cmac {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa906
+    ""
+    233f464f6f4fed40;
+  0d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    1f
+    f80086d1f74c3c25;
+  337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    6057acc87638f508046733d9ff61cdbda3b3e9878731ebfe
+    88141768f1834980;
+  dd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450
+    727a9b542cde52ebfda19d0ccc520f215eb57b
+    8b2e3c8554c039c5;
+  b3a4f3ebbbb18ac6c95a97
+    ""
+    992c2d7bae553fa1;
+  a48030370c33d090c54215
+    ab
+    3ef759021e0bd2c2;
+  d6b3ad54efc9a38378c5b9
+    3bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac
+    7ef83257367f4dcf;
+  26afa3349829b94586306f
+    ed54154f8f28523c03d4de1600157846b710ee
+    595b0c57e4ecd664;
+  72807a2219
+    ""
+    c17ded27f35e843b;
+  bfb474fd71
+    d8
+    063d632b053cfb61;
+  91f24bb65d
+    1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbac
+    aefe8538008cd029;
+  a48b77dba1
+    89196d1ebba10b0467cb9fc2712a199e533fa9
+    296073d2f0263834;
+  156308cdec3f768281e040a9b9a222bd689aef66f5306c
+    ""
+    fc5dcde84c290e8e;
+  eb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb
+    0b
+    f0e70394d6b143c9;
+  ad7d95214ade49cb3b6f5fe8368131115c037ba323fe1d
+    c8151784873f0eb5b647da6794c18b5337685a96ed65b9ac
+    a9be9c5120820347;
+  a338527ef19b09c063c46f88de9fd41e72d7b97e23e6ea
+    bdff3bcd211499268878dbf30f1dad89d4b9b1
+    a54fb7e239aeec4c;
+}
+
+blowfish-ccm {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa906
+    0d2d4b
+    ""
+    ""
+    ""
+    c25c474f;
+  6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f
+    29549e
+    6b
+    ""
+    ""
+    57a5a9c3;
+  0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638
+    f50804
+    ""
+    67
+    f4
+    62383997;
+  33d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7
+    f65b000961
+    040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f
+    215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    71ecbda26749ad4076aec1c63db0b7dcec21cf7a4861d69c
+    fb8186360d67254d;
+  4215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28
+    523c03d4de
+    1600157846b710ee72807a2219bfb474fd71d8
+    91f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbac
+    fa1e4cf72580563be4989ec3530f64fe6b897d54ed59da433615948331
+    93d5c6d564e86652;
+  a48b77dba189196d1ebba1
+    0b0467
+    ""
+    ""
+    ""
+    63379d2c;
+  cb9fc2712a199e533fa915
+    6308cd
+    ec
+    ""
+    ""
+    0a7f855f;
+  3f768281e040a9b9a222bd
+    689aef
+    ""
+    66
+    96
+    d2ba74d4;
+  f5306ceb0c6b08ac8b0a22
+    260c571b4a
+    42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836
+    8131115c037ba323fe1dc8151784873f0eb5b647da6794c1
+    458b929afd86f86db6c134400b0d1522882e10660e925b2d
+    0c69aa29dde98aa1;
+  8b5337685a96ed65b9aca3
+    38527ef19b
+    09c063c46f88de9fd41e72d7b97e23e6eabdff
+    3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952
+    5b680782d41f7d46c44d3811c313892f486f1597ed60dc10f15d1c43d5
+    327a56fa715955fc;
+  d22bb02d71
+    00b8b6
+    ""
+    ""
+    ""
+    6eaeedf7;
+  49377d20a8
+    f08345
+    5b
+    ""
+    ""
+    eb64c104;
+  663e4ee131
+    5f3c8f
+    ""
+    2a
+    22
+    87151792;
+  ebfa921451
+    dcd1af5813
+    b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584
+    b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16
+    58be2a1ed2225be8ef09f86202a312b01b829eb7e326b926
+    88f7ac759bdd6989;
+  cb16c2e815
+    f422cdf0c8
+    e30308be3c31e6bc58c0b7cadcb658b970e474
+    79a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70
+    49058d3fde34557441cc9b3e231c87043a5741c3eb99cc2bc58b5f4b6f
+    87c25970fcee3bba;
+  e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784
+    e0c6f2
+    ""
+    ""
+    ""
+    16bd95ba;
+  1195a3b9f4ae985511265febd11c164720eef9eb1c8dd0
+    b00951
+    f2
+    ""
+    ""
+    44763b0a;
+  84649016ed00456331854bc78bf43966eb0cfa9138ddc3
+    990844
+    ""
+    56
+    b4
+    8072f963;
+  08fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d1
+    26b807e6da
+    a089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973
+    a8cd190107314717a77456f3ff669c732b58db8f48af65f7
+    86876ace214551f65de8ef07460bc5c70638989bc14365c7
+    1347b1b46e131d8e;
+  cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b387
+    66fc69f6a9
+    f2c0945ffd505003cc0cae9ce021a5f1fa4ffa
+    91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff67785
+    0f2d12a0832a56f1640d37b17c901d899e2fa4678c867664380cd31062
+    596d1ddc3b997e5a;
+}
+
+blowfish-eax {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa906
+    ""
+    ""
+    ""
+    ""
+    a6e2fbebaf974200;
+  0d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    1f
+    ""
+    ""
+    ""
+    4cc58c2f4cf91137;
+  337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    ""
+    60
+    ""
+    ""
+    c35fc08fda46f599;
+  57acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb95295
+    ""
+    ""
+    33
+    9c
+    b7c0dcb87a8b86c9;
+  966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030
+    370c33d090c54215
+    abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb6
+    48e27fff63102758fe2b69ac26afa3349829b94586306fed
+    783ab2ee6ea73b63906caf73ceb4376b2e9ebee34fc490c5
+    3fff7a36718ab82c;
+  54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df
+    9fcbaca48b77db
+    a189196d1ebba10b0467cb9fc2712a199e533f
+    a9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac
+    43bfef92d8c8ba5641fb2523e92ef24d60a41da2e8bb3112aee7b80ce3
+    07ad2ca904227df7;
+  8b0a22260c571b4a42bb8f
+    ""
+    ""
+    ""
+    ""
+    bd94df689662060a;
+  db233bfa6a5cfb0bad7d95
+    21
+    ""
+    ""
+    ""
+    a43ffffe35e1b8a4;
+  4ade49cb3b6f5fe8368131
+    ""
+    11
+    ""
+    ""
+    d32da332498a6950;
+  5c037ba323fe1dc8151784
+    ""
+    ""
+    87
+    12
+    0943c4cb5e3fc7eb;
+  3f0eb5b647da6794c18b53
+    37685a96ed65b9ac
+    a338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabd
+    ff3bcd211499268878dbf30f1dad89d4b9b12012e4713df4
+    aebee82a01e138a7229636ee0eb746f6ce13584936f56bb4
+    5bddd65c9a111ec7;
+  6795630e7952d22bb02d71
+    00b8b649377d20
+    a8f083455b663e4ee1315f3c8f2aebfa921451
+    dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584
+    8a298eafedf8c1e183dfa50569cda59c9f93e56fde173e750e2fa185c7
+    78a05a55f474688a;
+  b7c5e61766
+    ""
+    ""
+    ""
+    ""
+    6e8da28b2d84682a;
+  9c0f16e398
+    15
+    ""
+    ""
+    ""
+    a6660ae3f78c52b7;
+  d4e9cfce3e
+    ""
+    d1
+    ""
+    ""
+    caa08d52fd0d87cf;
+  ecdf3d264a
+    ""
+    ""
+    7f
+    b7
+    af92632b8a903cfd;
+  16cb16c2e8
+    15f422cdf0c8e303
+    08be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69
+    a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e
+    773aeb0f1ffbc8b9f0a642275761a79598ab37c4a531e157
+    7b4483789e1768fc;
+  98ef1f0446
+    b42fb144d44b6d
+    00f06dc188d472a784e0c6f21195a3b9f4ae98
+    5511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331
+    08d772c882d1d700f980b349e40c3cb563743f62b966fe38ce39831c37
+    62662279f37c6a9b;
+  854bc78bf43966eb0cfa9138ddc39908445608fe95e81c
+    ""
+    ""
+    ""
+    ""
+    99eb415cd27dfb9d;
+  2533e31c9c1a9851bc2810d858cbbc8424d126b807e6da
+    a0
+    ""
+    ""
+    ""
+    c90ad3bb5ff737a9;
+  89c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973
+    ""
+    a8
+    ""
+    ""
+    dc32c7a1d4f99131;
+  cd190107314717a77456f3ff669c732b58db8f48af65f7
+    ""
+    ""
+    cc
+    86
+    5a32c09bf86a0f69;
+  9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766
+    fc69f6a9f2c0945f
+    fd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b
+    9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf127
+    c9d09215bfda6368733b83186710d656bd900f072a02173d
+    1e35ed44860e1cb0;
+  0485b203a3c1c4c967c0a458cb948bdd409b687fa3a682
+    7b480aa3a4c84c
+    ef64f6c9b53bf8f957f4b03cf43e89957f9a3e
+    8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf
+    1b485cb8f21d2744e6fdb19989d90693a8d2b935d0eae05facba546e91
+    8b86611191b4bdf3;
+}
+
+blowfish-gcm {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa906
+    ""
+    ""
+    ""
+    ""
+    6b5ff4ee552b5221;
+  0d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    1f
+    ""
+    ""
+    ""
+    88af455e5264ee42;
+  337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    ""
+    60
+    ""
+    ""
+    3349c44a62931118;
+  57acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb95295
+    ""
+    ""
+    33
+    10
+    0084f273223d1321;
+  966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030
+    370c33d090c54215
+    abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb6
+    48e27fff63102758fe2b69ac26afa3349829b94586306fed
+    e506b433f4b8d79455ba85c9495a93fbdfd6d9b8905ff540
+    3a7eae4ca30b331e;
+  54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df
+    9fcbaca4
+    8b77dba189196d1ebba10b
+    0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5
+    300fa70b6ef7bfd848bb6686af20bd3fdd3c24870e4b3e27ebe638a6574f74666b
+    3c7cd92967f27b1b;
+  306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f
+    0eb5b647da6794
+    c18b5337685a96ed65b9aca338527ef19b09c0
+    63c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1d
+    5a4f347d4d422000d0df51f4cb24b0be321466d6730f7a811e36dc030c
+    15585b78049dd4fe;
+  ad89d4b9b12012e4713df4
+    ""
+    ""
+    ""
+    ""
+    fe363b1f2ccd1251;
+  6795630e7952d22bb02d71
+    00
+    ""
+    ""
+    ""
+    9b93dde4b132c750;
+  b8b649377d20a8f083455b
+    ""
+    66
+    ""
+    ""
+    bbc2c3a8d6d3ee89;
+  3e4ee1315f3c8f2aebfa92
+    ""
+    ""
+    14
+    e6
+    66a62c95caa9cbfb;
+  51dcd1af5813b70d30ce2f
+    1fef6ef315d07983
+    91805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9
+    cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308
+    2f5da54ea8b3beafd0f3dd6ac4e10650dd2ed421f8ce5ec1
+    9ce22826bbc14984;
+  be3c31e6bc58c0b7cadcb6
+    58b970e4
+    7479a684b5aefa69a4cd52
+    147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d
+    e1b7effaaf9fd5e129cfc598bc26a0100ea9bac25c51aeabb75a7127e05c1bc9bc
+    ae765f924e885d78;
+  00f06dc188d472a784e0c6
+    f21195a3b9f4ae
+    985511265febd11c164720eef9eb1c8dd0b009
+    51f284649016ed00456331854bc78bf43966eb0cfa9138ddc399084456
+    6bc0e656e9939d5fe58ad77acbcec603f5111cbe660d6b62d1c241ba6c
+    47b8a5c7cd546e34;
+  08fe95e81c
+    ""
+    ""
+    ""
+    ""
+    70b8e6f27adb97d9;
+  2533e31c9c
+    1a
+    ""
+    ""
+    ""
+    f334ea3a3b8ec059;
+  9851bc2810
+    ""
+    d8
+    ""
+    ""
+    802c25c30e3c0441;
+  58cbbc8424
+    ""
+    ""
+    d1
+    79
+    74d9b3cdc4ce7003;
+  26b807e6da
+    a089c3f9099c5ffb
+    824173d7634c04226f30cbb7f0e4a973a8cd190107314717
+    a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b7
+    f9e5d38f1d9ce21dc3b940af936de5b80b4ac4b034adb539
+    33d122be105fb43e;
+  30374ffc9b
+    c597f56c
+    cbb2f294b38766fc69f6a9
+    f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e3
+    9895b89d611def800949f45f4e61129a3722df9b15f37afca829d4fc08266acf57
+    7ac2cc22e1d5568d;
+  2d65cc1770
+    a18cbfe6effd1f
+    f6778554acf1270485b203a3c1c4c967c0a458
+    cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b0
+    bb5e83aa69b5356dceec0fe74656f2e4399e12c85e09dd2f8fb609c72a
+    2b642aa6511caace;
+  3cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b
+    ""
+    ""
+    ""
+    ""
+    991808a4cd53e573;
+  70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac84
+    51
+    ""
+    ""
+    ""
+    12bc329cc3ff10a9;
+  399587011677508a15dde524af3e2bee0646541a42c2ec
+    ""
+    cc
+    ""
+    ""
+    7ebd5d67b3fed4e4;
+  b44d65bad397abfaf529ee41cf9a05c7efedef3401539c
+    ""
+    ""
+    51
+    1e
+    6b6575eab9424e98;
+  d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a
+    5718fd25014107c8
+    e7d715a92add9589d1f5c054b2d983514605ec590294a319
+    b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70
+    4c86b78d99617ef3a0e2ba3306379b71221b44b4f53f5526
+    7cb8282ea97b3894;
+  d17d4569eaff59a332ba58d5d5589bfe079753ee1a957e
+    b6d6699e
+    6b7ea2725cb2dac07ecde9
+    5759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9
+    9001bbc3c0a5c6447968b8eec61f2e49ca7129b0560ea49201d997d682bc36984f
+    0c14462ce512a43d;
+  cf44bbc8c6254d980398bd94e66eb4563d405e51881e99
+    027b8ab9aea3cc
+    f860b0009740763d96836c5f87b95460938de1
+    288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7
+    3bf9da6973a8dc56cebcb99962a74dc8638d11f4cb1d932162cd63136e
+    ff4072c9c5180f17;
+}
+
+blowfish-ocb1 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa906
+    0d2d4b6003062365
+    ""
+    ""
+    ""
+    5f3f51e08130263d;
+  b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d
+    27a4ba234085406a
+    61
+    ""
+    ""
+    8de51300e0d17d9d;
+  36512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbd
+    a3b3e9878731ebfe
+    ""
+    dd
+    11
+    1baa12d5cdfeeee5;
+  4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa45072
+    7a9b542cde52ebfd
+    ""
+    a19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030
+    c1901311bcbe5d48115af605ce28802572f30dff577e27ec
+    330d726cadffef1c;
+  370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306f
+    ed54154f8f28523c
+    03d4de1600157846b710ee72807a2219bfb474fd71d891f2
+    4bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df
+    0a2dd79bb802baad38fb7e60e979c30bbbbcae5e5bfe515d
+    0ee0e2a8987f11b4;
+  9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac
+    8b0a22260c571b4a
+    ""
+    42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c03
+    0f42a8f34bf068232057195d449b9414f3bb33a692bff50f90f86b2d83
+    6cfb2c8b4b3ac1f8;
+  7ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3b
+    cd211499268878db
+    f30f1dad89d4b9b12012e4713df46795630e79
+    52d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa
+    eda7fb91f70e24d3ac9751e7132f6b104e41392dac28bf4f0e5daaa2b6
+    04f7c455e5d023ab;
+  921451dcd1af5813b70d30
+    ce2f1fef6ef315d0
+    ""
+    ""
+    ""
+    4a33cb478b8f393b;
+  798391805da08da3aefc5f
+    8584b7c5e617669c
+    0f
+    ""
+    ""
+    8745d6a0c38b7bb0;
+  16e39815d4e9cfce3ed1ec
+    df3d264a7f16cb16
+    ""
+    c2
+    3c
+    20ab4fe539c6b1ef;
+  e815f422cdf0c8e30308be
+    3c31e6bc58c0b7ca
+    ""
+    dcb658b970e47479a684b5aefa69a4cd52147ed12ca98698
+    bc0a5d98e5825c5e804c67213a1d820e29ef7dfddab70a5f
+    40854bd91c065d0d;
+  1a874498ad0abef8bc4fcb
+    70e27e98ef1f0446
+    b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4
+    ae985511265febd11c164720eef9eb1c8dd0b00951f28464
+    1a2ad5ef98fce431c6e9e85fdd057e59d2954f8e96bbadc8
+    979de99c867f2951;
+  9016ed00456331854bc78b
+    f43966eb0cfa9138
+    ""
+    ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d1
+    78687a94824bb12dfe6e650544f042524ead2780a8bb4dde09d3621ec4
+    d8dd93d379eb140f;
+  26b807e6daa089c3f9099c
+    5ffb824173d7634c
+    04226f30cbb7f0e4a973a8cd190107314717a7
+    7456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc5
+    b58e5fed2f88013418795c660e6e4b5ae3262382a534d79656c02a42f1
+    7391763bfa5e91d1;
+  97f56ccbb2
+    f294b38766fc69f6
+    ""
+    ""
+    ""
+    de47841b0e181038;
+  a9f2c0945f
+    fd505003cc0cae9c
+    e0
+    ""
+    ""
+    9e1855698acdf3f7;
+  21a5f1fa4f
+    fa91544485f1a125
+    ""
+    8b
+    46
+    279f95fd345d8d07;
+  2b9b8f0911
+    e32d65cc1770a18c
+    ""
+    bfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458
+    6abecbf72aed482a6f80d57b236c40d316e20362f5561ff6
+    cc8e958357592f6f;
+  cb948bdd40
+    9b687fa3a6827b48
+    0aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e
+    8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9
+    322b60b89783b356ffcddc812e11459c1841d1540a91057d
+    48feb980547cfd06;
+  e9a79b1abf
+    91b0851e5ca605ac
+    ""
+    8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65
+    735b81e7bf11cb6e02de6657d638e735c41336f7d021d1e6b07c8aaa69
+    f21aba6b029d81a5;
+  bad397abfa
+    f529ee41cf9a05c7
+    efedef3401539c51d2a90bbf7f1bfc338ab0ef
+    5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1
+    094621285cf10b55b5c7ac0287f2267a8b4f9fecdd2e4107a88c16bd91
+    0a2c24953366e55d;
+  f5c054b2d983514605ec590294a319b9802068a9f891bc
+    5ba5afabf8c3122d
+    ""
+    ""
+    ""
+    c9a161d460c36f70;
+  12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589b
+    fe079753ee1a957e
+    b6
+    ""
+    ""
+    60dd373e888b983a;
+  d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7ab
+    c8ad68daac90cfe2
+    ""
+    2d
+    34
+    f2b20b2e78622af4;
+  2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d98
+    0398bd94e66eb456
+    ""
+    3d405e51881e99027b8ab9aea3ccf860b0009740763d9683
+    1d2773587c73b701d3cc8beb604ce8f285046e6879e5c0e5
+    ba34965f7a472a8f;
+  6c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e
+    86041c1b9fc214e9
+    ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c
+    36800d9645563a308ba60076817523bd2abf1261b089d8f2
+    b0d06d7557017e3cd08c88a3a3d744ec0d7d964e72197911
+    9de86854fdf00689;
+  3a9c2835076a23faac2cdd67771cc667a8331f0a170b66
+    283e4f834a06148f
+    ""
+    302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b3
+    f91ee277a3c2b93ce6c8df23263fd829225d66ff7f8bba9612230e8bf1
+    d2c7d587cbddcddd;
+  3779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2
+    b94b0820cab383a8
+    cffeea7c486315799dc875fba578c8ec483789
+    8a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14
+    00e25b2c5fdee0b87cd2c66474f852256a4e3b6239ef6ba512af0f74c0
+    5711f23d4b34df7f;
+}
+
+blowfish-pmac1 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa906
+    ""
+    db56f7585ef1b3ea;
+  0d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    1f
+    fe51530be20f5059;
+  337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    6057acc87638f508046733d9ff61cdbda3b3e9878731ebfe
+    370a72ba02c69145;
+  dd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450
+    727a9b542cde52ebfda19d0ccc520f215eb57b
+    b31c99831d7ad455;
+  b3a4f3ebbbb18ac6c95a97
+    ""
+    41939f3db560fdb4;
+  a48030370c33d090c54215
+    ab
+    d56476908d8efe7a;
+  d6b3ad54efc9a38378c5b9
+    3bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac
+    7f864cbc1bee3343;
+  26afa3349829b94586306f
+    ed54154f8f28523c03d4de1600157846b710ee
+    a344715c78dc0063;
+  72807a2219
+    ""
+    78e276b95d095a71;
+  bfb474fd71
+    d8
+    9b5c25004d486060;
+  91f24bb65d
+    1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbac
+    1d4dbe26bc70c6bc;
+  a48b77dba1
+    89196d1ebba10b0467cb9fc2712a199e533fa9
+    3b97fb336799efbd;
+  156308cdec3f768281e040a9b9a222bd689aef66f5306c
+    ""
+    cc20b90115cd712c;
+  eb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb
+    0b
+    eb75059c3f5ccc65;
+  ad7d95214ade49cb3b6f5fe8368131115c037ba323fe1d
+    c8151784873f0eb5b647da6794c18b5337685a96ed65b9ac
+    f0576e12bc1af195;
+  a338527ef19b09c063c46f88de9fd41e72d7b97e23e6ea
+    bdff3bcd211499268878dbf30f1dad89d4b9b1
+    e193575442a800ab;
+}
+
+blowfish-ocb3 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa906
+    0d2d4b600306
+    ""
+    ""
+    ""
+    b3583d3de56211f4;
+  2365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e
+    6b0d27a4ba23
+    40
+    ""
+    ""
+    912c60b4f34b6731;
+  85406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9
+    ff61cdbda3b3
+    ""
+    e9
+    dd
+    49ef753d0e5893dc;
+  878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9
+    b2fc5f
+    ""
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3
+    104cef2c140c06f2a9c502bd63c02be3d940a76e94b52e8e
+    2279d2765293b605;
+  ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac
+    26afa33498
+    29b94586306fed54154f8f28523c03d4de1600157846b710
+    ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b
+    e2f8d8fe5551cca9b88351ee9e422ceb2ed4abfaca8fa2b8
+    4cce00e139bd21d6;
+  571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a2
+    22bd689aef66
+    ""
+    f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d
+    e4fddb14c2c34d5695f13bdc9e21f6ff4605c864e2e7b0550606d5f478
+    c07b9776137a4225;
+  95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c4
+    6f88de9fd41e
+    72d7b97e23e6eabdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b64937
+    c64055e9e272881679259cd8f6d67f2291cea67a6865f4af686f02f032
+    32eace6f457de00d;
+  7d20a8f083455b663e4ee1
+    315f3c8f2aeb
+    ""
+    ""
+    ""
+    99933637fa8f2b85;
+  fa921451dcd1af5813b70d
+    30ce2f1fef6e
+    f3
+    ""
+    ""
+    b6e8c9c6a45b2a56;
+  15d0798391805da08da3ae
+    fc5f8584b7c5
+    ""
+    e6
+    80
+    3facc6b40f6e5187;
+  17669c0f16e39815d4e9cf
+    ce3ed1
+    ""
+    ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6
+    859387df0c8d6efe243bba8c894f17fa1935f42cd6148235
+    4d1dd56b61f0988b;
+  bc58c0b7cadcb658b970e4
+    7479a684b5
+    aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb
+    70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784
+    ebf8c0ff4e24b5754891cff817c499efa87b8a9fdf0d2cc1
+    1d3775fe8dc794e7;
+  e0c6f21195a3b9f4ae9855
+    11265febd11c
+    ""
+    164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966
+    cc19d5c325f9e65a669dc5e47d9ebfc15d3a3f609d8a96bf9d6eb710fa
+    dba9d363c65b7e0b;
+  eb0cfa9138ddc399084456
+    08fe95e81c25
+    33e31c9c1a9851bc2810d858cbbc8424d126b8
+    07e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd
+    53fd73e769e423e95ea852b9f025096cff34e3d1902ff701cdf24790c8
+    eb3ca419114e51fe;
+  1901073147
+    17a77456f3ff
+    ""
+    ""
+    ""
+    be3a587aad834d02;
+  669c732b58
+    db8f48af65f7
+    cc
+    ""
+    ""
+    2d749c7591283c5c;
+  9e3fb90e17
+    21b730374ffc
+    ""
+    9b
+    43
+    0e0346447f445eca;
+  c597f56ccb
+    b2f294
+    ""
+    b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa
+    06da8393393846121625c231930a8490f2a4ce8b89447e2b
+    78e64ea8e4df5f24;
+  4ffa915444
+    85f1a1258b
+    2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1
+    270485b203a3c1c4c967c0a458cb948bdd409b687fa3a682
+    8f7152ef08106003140fd22ae1d7911123b04337f8e2cff6
+    c3c1d8284b448b74;
+  7b480aa3a4
+    c84cef64f6c9
+    ""
+    b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd20
+    d0d64b53c566f1dc431a72dda89c51a7b7d25a57638af924b7f56d75e7
+    c691e0e094254334;
+  5b70e04c09
+    1d205cdad9e9
+    a79b1abf91b0851e5ca605ac84513995870116
+    77508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529
+    b930562d3cc00abaeaa1dc8ff5825cdf086e0ba72916c06d9bd4f837bd
+    90343080f7fb1dda;
+  ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338a
+    b0ef5746ea8f
+    ""
+    ""
+    ""
+    91f6852537252f8a;
+  dcccd213e33f7e8a5718fd25014107c8e7d715a92add95
+    89d1f5c054b2
+    d9
+    ""
+    ""
+    b36663b6367ef6ef;
+  83514605ec590294a319b9802068a9f891bc5ba5afabf8
+    c3122d12d7ff
+    ""
+    3c
+    e5
+    1961c689d2d77714;
+  41122d70d17d4569eaff59a332ba58d5d5589bfe079753
+    ee1a95
+    ""
+    7eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7
+    cb0853f95fc84b810db7f3b9518d6c1a1ef5e78a3d316746
+    5b65e59ea9a723f0;
+  abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb35
+    42a9cf44bb
+    c8c6254d980398bd94e66eb4563d405e51881e99027b8ab9
+    aea3ccf860b0009740763d96836c5f87b95460938de1288c
+    fbd80f2a162c319b91c99ed4a0f8860cbad42c59792cf7ac
+    35dac492225424a6;
+  69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186
+    ddf1f6a7a3aa
+    ""
+    7e740da967828e3604b35b15ffaa6c36800d9645563a308ba600768175
+    75bef1ae59a3404b09299f06461e0cbb3a9d6e58d4f49928f9b0845f01
+    f93d21e578e90e18;
+  23bd2abf1261b089d8f23a9c2835076a23faac2cdd6777
+    1cc667a8331f
+    0a170b66283e4f834a06148f302c3973accd56
+    f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc
+    6128d1bdba407d841d26fb849b2f1967f1877822a75c402b845bd5f1b1
+    2951dd60e7a50fe4;
+}
+
+blowfish-ocb3-mct {
+  56 1eaefdb48ac7e8be;
+  52 b79553ab012d6259;
+  48 e596561501cbb1d1;
+  44 0b3d0dd4007cc8e1;
+  40 5e01c4481579151f;
+  36 f745536adb730368;
+  32 261481ed1915729e;
+  28 b6fa034db1ed80e8;
+  24 0b7aed4db823ce0c;
+  20 472a7cbbc3b93999;
+  16 4434cb1c40f21097;
+  12 4f64439b9bcedfc2;
+  10 654a7c2699f7e4db;
+   8 b0d1574724b61c02;
+  56 883bad05122a;
+  52 1cf7ba9a0e86;
+  48 44d9c92bfb48;
+  44 2ab05efeab38;
+  40 fb1788302233;
+  36 926b61ed2153;
+  32 d240e2d8b6e9;
+  28 6a7452bc8c50;
+  24 7be498392971;
+  20 90d3cb1c76c2;
+  16 a4ce66e48d8f;
+  12 15a879e95625;
+  10 2af8e886f690;
+   8 c3ecbf857159;
+  56 f196b27c;
+  52 84c6f8e6;
+  48 2323c6f4;
+  44 c3c03f9d;
+  40 57979457;
+  36 318c4335;
+  32 1928bd41;
+  28 cb2429ec;
+  24 369cdefd;
+  20 45e7c011;
+  16 32768164;
+  12 469cab17;
+  10 17a3dd1d;
+   8 a4a15a19;
+}
index a456ea0..7ea4b47 100644 (file)
@@ -13,3 +13,912 @@ cast128 {
   0123456789abcdef
   7ac816d16e9b302e;
 }
+
+cast128-cmac {
+  60d7bcda163547d348b7551195
+    ""
+    e027f02068e914e0;
+  e77022907dd1dff7dac5c9941d
+    26
+    a28361e0bd2c591c;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0
+    4eeb71793dd20683;
+  a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff
+    f46b0adba4856f4f;
+  77bf79192a5b50
+    ""
+    79360635503a7f04;
+  ade5d9cd739a3d
+    1f
+    9a100ee7cd214433;
+  337f29549e6b0d
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f
+    81e6063cc8dd3e25;
+  2dd88374d8cde8
+    e160ad10997a21635c6d62c9269029df3e6057
+    077ce3be2b167375;
+  acc87638f508046733d9
+    ""
+    e0ac1c1c71776fcb;
+  ff61cdbda3b3e9878731
+    eb
+    de618ec3a0d64ca2;
+  fedd4705e505da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    1b5ed15a16456292;
+  966f27043eb621b7f65b
+    000961040ef2f9b2fc5fa450727a9b542cde52
+    fe228a47df7c250d;
+  ebfda19d0ccc520f21
+    ""
+    e8d3cb82a354843c;
+  5eb57bb3a4f3ebbbb1
+    8a
+    c7fcbad7ee9257d3;
+  c6c95a97a48030370c
+    33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    1d547d096465faf6;
+  5faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b9458630
+    10bd2c18c3337a4f;
+}
+
+cast128-ccm {
+  60d7bcda163547d348b7551195
+    e77022
+    ""
+    ""
+    ""
+    4905fdcf;
+  907dd1dff7dac5c9941d26d0c6
+    eb14ad
+    56
+    ""
+    ""
+    327786b3;
+  8f86edd1dc9268eeee533285a6
+    ed810c
+    ""
+    9b
+    7d
+    9d869519;
+  689daaa9060d2d4b6003062365
+    b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9f137120634c95198
+    48a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e
+    c935111d2f5913c3a992e7b11d538a1f5750237258739dd7
+    ccae7a45efc12caf;
+  6b0d27a4ba234085406a613651
+    2061f7080c
+    c07df0591d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbd
+    9bd2a0c0f027a5a1b56974b85be03dd3ffe81b5f2a2381170fb7eca747
+    711646ef1dde6cad;
+  a3b3e9878731eb
+    fedd47
+    ""
+    ""
+    ""
+    af3e6347;
+  05e505da1435dc
+    eaa7b1
+    cc
+    ""
+    ""
+    571ec017;
+  49ae1d50c38201
+    a89447
+    ""
+    6b
+    1b
+    1859fcd4;
+  3f102b752eb952
+    9533966f27
+    043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a
+    63f409a8d0dba1ec4c090efd260b557d0359482f69d62126
+    7d4b85fb7d13bf0c;
+  97a48030370c33
+    d090c54215
+    abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    aee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed
+    018425effd80fbb802f204bdefb41d4b2fa140dd2b2149580b72428bab
+    53bd8b75c9a3bc09;
+  54154f8f28523c03d4de
+    160015
+    ""
+    ""
+    ""
+    4397bfc8;
+  7846b710ee72807a2219
+    bfb474
+    fd
+    ""
+    ""
+    a28f8e1e;
+  71d891f24bb65d156325
+    9f9eb5
+    ""
+    3b
+    cf
+    185c4f64;
+  571ea629c54d57dd2d42
+    f70800df9f
+    cbaca48b77dba189196d1ebba10b0467cb9fc2712a199e53
+    3fa9156308cdec3f768281e040a9b9a222bd689aef66f530
+    030e417475032f357c1257444a95486a4e0e652beb78ee50
+    a36e60d6e4fffa0d;
+  6ceb0c6b08ac8b0a2226
+    0c571b4a42
+    bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b
+    6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b
+    ae6c8d1d32a0ecff25eb9c81ff41dc0f31a9e9df6d96d7aa499a001ad1
+    cad9b682638f7a11;
+  5337685a96ed65b9ac
+    a33852
+    ""
+    ""
+    ""
+    cee2fb45;
+  7ef19b09c063c46f88
+    de9fd4
+    1e
+    ""
+    ""
+    f82a2ce3;
+  72d7b97e23e6eabdff
+    3bcd21
+    ""
+    14
+    8e
+    cf442fcb;
+  99268878dbf30f1dad
+    89d4b9b120
+    12e4713df46795630e7952d22bb02d7100b8b649377d20a8
+    f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b7
+    d3216e8ddc4bae39da814c7541496567ad7669f3ebfafba7
+    ffef801deb5ef8fd;
+  0d30ce2f1fef6ef315
+    d079839180
+    5da08da3aefc5f8584b7c5e617669c0f16e398
+    15d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c
+    d9f3345b6b1782cd1db09c53d2076a2b84f4cc16e94c58cb46cbd5d85e
+    c46139beb639552b;
+}
+
+cast128-eax {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    de756459eefbe735;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    706c2756289404eb;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    1dba9d384981a899;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    9c
+    e1c1cb285fe6fd42;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794
+    846ecfa14a7130c9f137120634c9519848a877ff77bf7919
+    2a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    7ea32c98c18f380ebf49a8153a036aba80fc8219ee85ea9a
+    678b76a28d6415ac;
+  406a6136512061f7080cc07df0
+    591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    21ed0355fd3256ebee4847ec0d0f6a024e6ea0f2cd8a5de1f5bb139385
+    d4a1d384f6234b97;
+  05e505da1435dc
+    ""
+    ""
+    ""
+    ""
+    cbbb9ef570741e49;
+  eaa7b1cc49ae1d
+    50
+    ""
+    ""
+    ""
+    f8c34e199b130f87;
+  c38201a894476b
+    ""
+    3f
+    ""
+    ""
+    76bfe7342f08a0d9;
+  102b752eb95295
+    ""
+    ""
+    33
+    40
+    78d8ced34fba2669;
+  966f27043eb621
+    b7f65b000961040e
+    f2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215e
+    b57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215
+    2ab0a37f0ebd0523111d8079b33285016f8038eb01d8c726
+    2557d7fde2b5cbf4;
+  abd6b3ad54efc9
+    a38378c5b93bf4
+    f2aad2605faee2b03fb648e27fff63102758fe
+    2b69ac26afa3349829b94586306fed54154f8f28523c03d4de16001578
+    cde7aba02b6c423e5a4c5bee6592a8c6beedd60b458982ecb96ec2d05a
+    4b957468a1b84eaf;
+  46b710ee72807a2219bf
+    ""
+    ""
+    ""
+    ""
+    4c34faee63cc6ded;
+  b474fd71d891f24bb65d
+    15
+    ""
+    ""
+    ""
+    fe3d9bc8bb1fadc7;
+  63259f9eb53b571ea629
+    ""
+    c5
+    ""
+    ""
+    89349e8fa6362b16;
+  4d57dd2d42f70800df9f
+    ""
+    ""
+    cb
+    f0
+    3f45042252ade21c;
+  aca48b77dba189196d1e
+    bba10b0467cb9fc2
+    712a199e533fa9156308cdec3f768281e040a9b9a222bd68
+    9aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb23
+    b5c79faaecf9c2d65703aae2c578b606b455c25f6aec3a4b
+    fe3a14a18c793f8d;
+  3bfa6a5cfb0bad7d9521
+    4ade49cb3b6f5f
+    e8368131115c037ba323fe1dc8151784873f0e
+    b5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88
+    b8d413238c76153b01f0a2823e24414f91988638bf3a80cdb6a211700f
+    12e4967ff0500b9f;
+  de9fd41e72d7b97e23
+    ""
+    ""
+    ""
+    ""
+    caab65ebca9b09cd;
+  e6eabdff3bcd211499
+    26
+    ""
+    ""
+    ""
+    7fb3ef6dc33a52ea;
+  8878dbf30f1dad89d4
+    ""
+    b9
+    ""
+    ""
+    1781664543c4675f;
+  b12012e4713df46795
+    ""
+    ""
+    63
+    41
+    9d8c48bc137b207a;
+  0e7952d22bb02d7100
+    b8b649377d20a8f0
+    83455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d
+    30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5
+    bf81b5c1007332ff360b167545ff826c131e6279a40ec6f3
+    e037dbce43a14ff2;
+  e617669c0f16e39815
+    d4e9cfce3ed1ec
+    df3d264a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed1
+    9b3b606592501407cf47aa56b3136cca02d94d282ebf6d5f441b32b9f3
+    d8a34c6cae422b2c;
+}
+
+cast128-gcm {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    827e37433b2c1494;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    603a0e329e3029ed;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    09e36329c9190d21;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    0b
+    83b106e61ac95294;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794
+    846ecfa14a7130c9f137120634c9519848a877ff77bf7919
+    2a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    d83412ab72752e456aba4b235ea84e65d99a082caea1eba5
+    9ded1889068ab798;
+  406a6136512061f7080cc07df0
+    591d8fa2
+    1f2dd88374d8cde8e160ad
+    10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9
+    b0f1bd0e10c71ddab6c3c3a1b5cb5e0cf831042e831b12789ac9d617e21e573dac
+    8a619f19a69e0bff;
+  878731ebfedd4705e505da1435
+    dceaa7b1cc49ae
+    1d50c38201a894476b3f102b752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52eb
+    fa5b4ee08950d597fcb0affdf0f0aa8174ca0e9dcfc4ee13e4b5a2bae1
+    b6ce5f7d53e6177b;
+  fda19d0ccc520f
+    ""
+    ""
+    ""
+    ""
+    522de0429e89383a;
+  215eb57bb3a4f3
+    eb
+    ""
+    ""
+    ""
+    45fb1e234c4d8ccd;
+  bbb18ac6c95a97
+    ""
+    a4
+    ""
+    ""
+    89dab6195164787c;
+  8030370c33d090
+    ""
+    ""
+    c5
+    bd
+    870b563762624fec;
+  4215abd6b3ad54
+    efc9a38378c5b93b
+    f4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de160015
+    3cbe2ea8aa7c3ea77e46a9afbd7f69fc51f663820293720c
+    ff1dcf81a83ea960;
+  7846b710ee7280
+    7a2219bf
+    b474fd71d891f24bb65d15
+    63259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebb
+    f54b9538cef3257defa694754b7e196a132d042c670e72a1dcb527f660b836f098
+    59f1ff473e5232e6;
+  a10b0467cb9fc2
+    712a199e533fa9
+    156308cdec3f768281e040a9b9a222bd689aef
+    66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad
+    f8432f79ab5a3e07c7dff91e912d79f7e6b6828b8a10c74bf419d9448f
+    0ec34f0d7a1b4c11;
+  7d95214ade49cb3b6f5f
+    ""
+    ""
+    ""
+    ""
+    08185a4aee37b676;
+  e8368131115c037ba323
+    fe
+    ""
+    ""
+    ""
+    14a6486a55038a65;
+  1dc8151784873f0eb5b6
+    ""
+    47
+    ""
+    ""
+    598e10f99a3c9a58;
+  da6794c18b5337685a96
+    ""
+    ""
+    ed
+    39
+    fd918834389b1469;
+  65b9aca338527ef19b09
+    c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89
+    d4b9b12012e4713df46795630e7952d22bb02d7100b8b649
+    1c3d067c765e17b338cf91585a0caf2f70bc663db8274944
+    09ab5e3cd3740b16;
+  377d20a8f083455b663e
+    4ee1315f
+    3c8f2aebfa921451dcd1af
+    5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f
+    4b8874ad4cb500f61ff68c73c68dda4f440ad538ded72c0d5a265ce5721cf354f9
+    77bda550c71cc140;
+  16e39815d4e9cfce3ed1
+    ecdf3d264a7f16
+    cb16c2e815f422cdf0c8e30308be3c31e6bc58
+    c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a87
+    fba726477f0a66ba98a278b52e721b41ebb36556e59d2e9830e66fe0a1
+    9666883d3ef07a79;
+  4498ad0abef8bc4fcb
+    ""
+    ""
+    ""
+    ""
+    4417c135917f0b7e;
+  70e27e98ef1f0446b4
+    2f
+    ""
+    ""
+    ""
+    579b6455f429d389;
+  b144d44b6d00f06dc1
+    ""
+    88
+    ""
+    ""
+    c0feccc75a38a7ea;
+  d472a784e0c6f21195
+    ""
+    ""
+    a3
+    ba
+    d3e312ae74483320;
+  b9f4ae985511265feb
+    d11c164720eef9eb
+    1c8dd0b00951f284649016ed00456331854bc78bf43966eb
+    0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc
+    ececbe9f36ef004be708cf21bf97615f62e9ef58803fe723
+    57ac52bfb40dd355;
+  2810d858cbbc8424d1
+    26b807e6
+    daa089c3f9099c5ffb8241
+    73d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db
+    7dff8ee32fab541aa59bdccc84961db26644f6bd50773640afd3a22cd438f54026
+    916e18567fd17de8;
+  8f48af65f7cc9e3fb9
+    0e1721b730374f
+    fc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f09
+    3c6ea417e98fd5ed2874ef3b1d8b512fbbe5449541a8912afce6b85441
+    6c1dcdd2eef63a3e;
+}
+
+cast128-ocb1 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7
+    ""
+    ""
+    ""
+    35fcd5e38e3b51ae;
+  dac5c9941d26d0c6eb14ad568f
+    86edd1dc9268eeee
+    53
+    ""
+    ""
+    9750a7c045cb5fa6;
+  3285a6ed810c9b689daaa9060d
+    2d4b6003062365b0
+    ""
+    a5
+    70
+    2007ad9ceaa910e8;
+  4364c76c160f11896c4794846e
+    cfa14a7130c9f137
+    ""
+    120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    1d6fefbc39046f96c95a8e6a1b9dee24838ae0538c73cc2b
+    367e4bd46fea6528;
+  1f337f29549e6b0d27a4ba2340
+    85406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    21635c6d62c9269029df3e6057acc87638f508046733d9ff
+    0754a41170bb62612e1224d955d5c65fb33c4331487b17fc
+    bf7b46ca9365175f;
+  61cdbda3b3e9878731ebfedd47
+    05e505da1435dcea
+    ""
+    a7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    491c578a12863680495817bbb1be6bb5cd068da6c097a4d7454c4e8da0
+    d255ace5711af8ae;
+  21b7f65b000961040ef2f9b2fc
+    5fa450727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b9
+    97a20b90075f6b8cd05b2c101043d92167fd921a71668f63a3c1115b0f
+    202da1820f237005;
+  3bf4f2aad2605f
+    aee2b03fb648e27f
+    ""
+    ""
+    ""
+    31e566cec6e241d7;
+  ff63102758fe2b
+    69ac26afa3349829
+    b9
+    ""
+    ""
+    ca2c2e57da61fa0b;
+  4586306fed5415
+    4f8f28523c03d4de
+    ""
+    16
+    5d
+    85b6fa491dfc6955;
+  00157846b710ee
+    72807a2219bfb474
+    ""
+    fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d
+    737de7976152fc336878cbbb9ede5469e5cc5d970933fd65
+    8f8227129780dd53;
+  42f70800df9fcb
+    aca48b77dba18919
+    6d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f76
+    8281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22
+    f2320eca3b003b64b91066ab2de93cdd408517d8a9728db9
+    538a1fa6a7597e50;
+  260c571b4a42bb
+    8fdb233bfa6a5cfb
+    ""
+    0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc815178487
+    20c12e9ba584a56f7768fe92d9111a7eae80e149386c93d17f7904a41a
+    48e10cd0a8be13c9;
+  3f0eb5b647da67
+    94c18b5337685a96
+    ed65b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012
+    55e5fad364bb32f3fa056d496f84874281576e690d72fa33be655966e4
+    a0b5a442a7297a49;
+  e4713df46795630e7952
+    d22bb02d7100b8b6
+    ""
+    ""
+    ""
+    940a9694d41abe63;
+  49377d20a8f083455b66
+    3e4ee1315f3c8f2a
+    eb
+    ""
+    ""
+    7b6cad447bf0e593;
+  fa921451dcd1af5813b7
+    0d30ce2f1fef6ef3
+    ""
+    15
+    30
+    536c60f6f1d83c94;
+  d0798391805da08da3ae
+    fc5f8584b7c5e617
+    ""
+    669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e8
+    1c485850e9c9b37abb599a800973920b660fd62c31d374a4
+    3b5a7524db68ca3d;
+  15f422cdf0c8e30308be
+    3c31e6bc58c0b7ca
+    dcb658b970e47479a684b5aefa69a4cd52147ed12ca98698
+    1a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d4
+    097c9f86dc5ed84b2c4302fa4b10719337a1ee8feed7d101
+    8f642bc221b793b9;
+  4b6d00f06dc188d472a7
+    84e0c6f21195a3b9
+    ""
+    f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00
+    98a5dafa75c301e74727ecbba6a5047ed29491a660cef05ba70e74eaf4
+    eb2ef400c45349a9;
+  456331854bc78bf43966
+    eb0cfa9138ddc399
+    08445608fe95e81c2533e31c9c1a9851bc2810
+    d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f
+    b43644eaaa9f3060a3a2d0eb7b10f8829f2769eb4ceaed6b712550e71c
+    fb0381cb9425f488;
+  30cbb7f0e4a973a8cd
+    190107314717a774
+    ""
+    ""
+    ""
+    a084a9815a7601a4;
+  56f3ff669c732b58db
+    8f48af65f7cc9e3f
+    b9
+    ""
+    ""
+    2ee2f881784c0227;
+  0e1721b730374ffc9b
+    c597f56ccbb2f294
+    ""
+    b3
+    05
+    683231980af7d491;
+  8766fc69f6a9f2c094
+    5ffd505003cc0cae
+    ""
+    9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65
+    e4f05c8136721b99369335ba402941018889f1fe75f9cb76
+    88de859ee4e6c912;
+  cc1770a18cbfe6effd
+    1ff6778554acf127
+    0485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b
+    480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a
+    db871dcb9e6624a931cef6ffcbe61ebc77c8b60f19550476
+    a74df4d69c389e3e;
+  3e8128f8743d16687b
+    7bb8deb9bd205b70
+    ""
+    e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677
+    922755c3a636a359fcf8fbeda42c8de7d32d109c3d1e2bc6b7f7094e9b
+    f18c36d8b0f0d64b;
+  508a15dde524af3e2b
+    ee0646541a42c2ec
+    ccb44d65bad397abfaf529ee41cf9a05c7efed
+    ef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a
+    c06849ccf2b34ffd7b497fd8936add1cb570227aa304c345092739d18b
+    326e341574bedb1f;
+}
+
+cast128-pmac1 {
+  60d7bcda163547d348b7551195
+    ""
+    9908603f8e4ed537;
+  e77022907dd1dff7dac5c9941d
+    26
+    ab2e2df52a4ffd51;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0
+    3400ed5412e2c9f7;
+  a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff
+    0f106ec05825e141;
+  77bf79192a5b50
+    ""
+    536bca927005ffd1;
+  ade5d9cd739a3d
+    1f
+    f69b33db8f802d6e;
+  337f29549e6b0d
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f
+    0b99429b96428cb3;
+  2dd88374d8cde8
+    e160ad10997a21635c6d62c9269029df3e6057
+    0098d1d07d912367;
+  acc87638f508046733d9
+    ""
+    da9779d1609cb9e1;
+  ff61cdbda3b3e9878731
+    eb
+    00096e5430e6e2bd;
+  fedd4705e505da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    a91e29d999936af2;
+  966f27043eb621b7f65b
+    000961040ef2f9b2fc5fa450727a9b542cde52
+    1df06f8b2c0f4c39;
+  ebfda19d0ccc520f21
+    ""
+    78b9f4bb116ef26b;
+  5eb57bb3a4f3ebbbb1
+    8a
+    57afa587a9a123d5;
+  c6c95a97a48030370c
+    33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    d32f3f141a62efe1;
+  5faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b9458630
+    cab1db46326dab8b;
+}
+
+cast128-ocb3 {
+  60d7bcda163547d348b7551195
+    e77022907dd1
+    ""
+    ""
+    ""
+    80acf79035879e49;
+  dff7dac5c9941d26d0c6eb14ad
+    568f86edd1dc
+    92
+    ""
+    ""
+    c1c0b7cf9333abd0;
+  68eeee533285a6ed810c9b689d
+    aaa9060d2d4b
+    ""
+    60
+    b7
+    2ba34997b9b7c1e7;
+  03062365b0a54364c76c160f11
+    896c47
+    ""
+    94846ecfa14a7130c9f137120634c9519848a877ff77bf79
+    a50349e70f84c21e91ac4dae8e84334c4eded066c4906f46
+    044e9f72b51e120b;
+  192a5b50ade5d9cd739a3d1f33
+    7f29549e6b
+    0d27a4ba234085406a6136512061f7080cc07df0591d8fa2
+    1f2dd88374d8cde8e160ad10997a21635c6d62c9269029df
+    ff3c222bcd45bd08ed535a77e89023455b21fd6b198e5220
+    6078eab50bffcabf;
+  3e6057acc87638f508046733d9
+    ff61cdbda3b3
+    ""
+    e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a89447
+    c9cff5648431ab446232a4644f1c59af90abdc696868521a9632a765af
+    e993a7f8297d83bd;
+  6b3f102b752eb9529533966f27
+    043eb621b7f6
+    5b000961040ef2f9b2fc5fa450727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c
+    d94512471232da2099eee100523fb16bb45018f05f681f067aaf7af8d6
+    87dca8c2d5779501;
+  33d090c54215ab
+    d6b3ad54efc9
+    ""
+    ""
+    ""
+    da927642dafe6fd1;
+  a38378c5b93bf4
+    f2aad2605fae
+    e2
+    ""
+    ""
+    e890bed519c2bfc9;
+  b03fb648e27fff
+    63102758fe2b
+    ""
+    69
+    f6
+    a1e73f23ec2eddee;
+  ac26afa3349829
+    b94586
+    ""
+    306fed54154f8f28523c03d4de1600157846b710ee72807a
+    0cf707f93f9c389e7c78ef3e61d36d20604e1441b169fc9a
+    6febc37ff410bc6f;
+  2219bfb474fd71
+    d891f24bb6
+    5d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcb
+    aca48b77dba189196d1ebba10b0467cb9fc2712a199e533f
+    06e300b114e2b4bebe212cf694364bc44989b8cfe139b08a
+    b496b69d5f5f2406;
+  a9156308cdec3f
+    768281e040a9
+    ""
+    b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb23
+    0af7dab55d9223c86960d4b03e62b32f96a5c1ee581be399c93b15e789
+    97f72d7c401cf252;
+  3bfa6a5cfb0bad
+    7d95214ade49
+    cb3b6f5fe8368131115c037ba323fe1dc81517
+    84873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c0
+    a0f7f9f1e1934502280dfa21be7bd3eadab7541c17cccc03102dcb3454
+    22cc4588498bc2a5;
+  63c46f88de9fd41e72d7
+    b97e23e6eabd
+    ""
+    ""
+    ""
+    869d689f3cb451ab;
+  ff3bcd211499268878db
+    f30f1dad89d4
+    b9
+    ""
+    ""
+    10c4ca311ab0d4ea;
+  b12012e4713df4679563
+    0e7952d22bb0
+    ""
+    2d
+    ae
+    d91ecbfa408ed62c;
+  7100b8b649377d20a8f0
+    83455b
+    ""
+    663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f
+    447474323cef334fa9a0733f9dcca98a6f5f79b395392cea
+    9b75ce84a39e878e;
+  1fef6ef315d079839180
+    5da08da3ae
+    fc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d
+    264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0
+    4e006eb2b0cb5e16f592ac6c5601c80e7a97fb0725c1ca4f
+    adcac831efd97e58;
+  b7cadcb658b970e47479
+    a684b5aefa69
+    ""
+    a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446
+    9f8a879d391e2c63103be599717c39608d4f0d42ab0b17bb3515e1e210
+    d2579224689f1c51;
+  b42fb144d44b6d00f06d
+    c188d472a784
+    e0c6f21195a3b9f4ae985511265febd11c1647
+    20eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0c
+    87e39284c048d9c1660e5437f1cc86615724448c5c86d185b1a54bc05c
+    52b0cf04002f103f;
+  fa9138ddc399084456
+    08fe95e81c25
+    ""
+    ""
+    ""
+    08923b4787ecca64;
+  33e31c9c1a9851bc28
+    10d858cbbc84
+    24
+    ""
+    ""
+    9c2d888635429e4f;
+  d126b807e6daa089c3
+    f9099c5ffb82
+    ""
+    41
+    76
+    14aedb991bbdf5d5;
+  73d7634c04226f30cb
+    b7f0e4
+    ""
+    a973a8cd190107314717a77456f3ff669c732b58db8f48af
+    ec093b797db58fa9c9b88e58ffbde6f4f4c38fb6db25b117
+    3eeb6753ae39c984;
+  65f7cc9e3fb90e1721
+    b730374ffc
+    9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003
+    cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911
+    3ffec2f705cc006637248de55ef480c9401790a303ccd564
+    6d3b369a0699bf98;
+  e32d65cc1770a18cbf
+    e6effd1ff677
+    ""
+    8554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b
+    91e2b0612406d31b88b044f838e29dc4bc08492a9d8b73b1751f6eb210
+    d684fc47c7b172f0;
+  480aa3a4c84cef64f6
+    c9b53bf8f957
+    f4b03cf43e89957f9a3e8128f8743d16687b7b
+    b8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac84
+    f9bc629deb9e6dc3454415296389546e992975ef5c6dfba23357c06539
+    d4d1265b9cad7cee;
+}
+
+cast128-ocb3-mct {
+  16 d2434caa22748e97;
+  14 4dab36316a173b4c;
+  12 25b37d39f09b8f7b;
+  10 6ea2b818da01a012;
+   8 e4e0aa59657d2246;
+   6 29299e3845bdedad;
+   4 99594416fa91c2f7;
+  16 460ffc3b13c9;
+  14 ff7bc7e6be51;
+  12 e0a21b1ff4b7;
+  10 5062cd9b7b51;
+   8 5d40437352df;
+   6 22a0f6279d79;
+   4 429d09c799fc;
+  16 a42ad529;
+  14 9dec6cc9;
+  12 15803553;
+  10 5c50c831;
+   8 4a2e5743;
+   6 e10bbd1e;
+   4 4a6bf7e7;
+}
diff --git a/symm/t/cast256.local b/symm/t/cast256.local
new file mode 100644 (file)
index 0000000..a52ad88
--- /dev/null
@@ -0,0 +1,892 @@
+### Local tests for CAST256.
+
+cast256-cmac {
+  60d7bcda163547d348b7551195
+    ""
+    550f6aa2b500f5b19d32c63502e8448b;
+  e77022907dd1dff7dac5c9941d
+    26
+    198a435819e092069eaf3c5a455baf3c;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    2e7ac3fd9be8475d5b81a6f5fd3392e9;
+  34c9519848a877ff77bf79192a
+    5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    7bcad81a16a4c1d1cf5fc4f107d9e50c;
+  8374d8cde8e160ad10997a21
+    ""
+    50fdac1d477bd12e61df27c230eb0858;
+  635c6d62c9269029df3e6057
+    ac
+    8ac07980a2538da61bf9fdb8f9791197;
+  c87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    4e9a7999789a6d1041fd26295aaa4942;
+  21b7f65b000961040ef2f9b2
+    fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    ffbaaeeaf8f93c7c71c7708e21043c32;
+  4215abd6b3ad54ef
+    ""
+    d3fc1c69dbbe8a358f5f968f8e60047e;
+  c9a38378c5b93bf4
+    f2
+    d37b1e960767df9d502e6c942e90f39d;
+  aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    55f8a2b6e7bd774ff32cac26cee4f1ef;
+  bfb474fd71d891f2
+    4bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9f
+    d33ece086863448e6714580ec9f8d267;
+  c2712a199e533fa9156308cdec3f768281
+    ""
+    9b818524f8ebef2f840938b85c30b9b8;
+  e040a9b9a222bd689aef66f5306ceb0c6b
+    08
+    44a2b05a0953086b802e5dfbccef8691;
+  ac8b0a22260c571b4a42bb8fdb233bfa6a
+    5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    ffa9d762bb11005e32a5747de41738c2;
+  b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    4e21bb0835d28d84b50e6db35757d672;
+}
+
+cast256-ccm {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9
+    ""
+    ""
+    ""
+    aa9a4a79;
+  941d26d0c6eb14ad568f86edd1
+    dc9268eeee533285a6ed81
+    0c
+    ""
+    ""
+    c8a39dd0;
+  9b689daaa9060d2d4b60030623
+    65b0a54364c76c160f1189
+    ""
+    6c
+    2d
+    73e78af5;
+  4794846ecfa14a7130c9f13712
+    0634c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    af2bcbe02785e26888000200221db7ec8a96262bd4ac58f98de028ac5f0ab12ff4a6525254d7f78215727c2796d9de34
+    d83e04bccd4cc28ee89db0528d559b4c;
+  05e505da1435dceaa7b1cc49ae
+    1d50c38201a894476b
+    3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0c
+    cc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb6
+    ae26d7c0fe93d7f36b4fe471099e64f0da7e0436df67adc9fbccbb9d12e26b9f086c3176ed28861c7d9afcfdb181dddb5b337c84b9
+    4eb8907ccd4025021d7117364de8c4f9;
+  48e27fff63102758fe2b69ac
+    26afa3349829b94586306f
+    ""
+    ""
+    ""
+    dcee39b3;
+  ed54154f8f28523c03d4de16
+    00157846b710ee72807a22
+    19
+    ""
+    ""
+    d0f09e35;
+  bfb474fd71d891f24bb65d15
+    63259f9eb53b571ea629c5
+    ""
+    4d
+    b1
+    20282dc8;
+  57dd2d42f70800df9fcbaca4
+    8b77dba189196d1ebb
+    a10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c57
+    1b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da67
+    9991d3ac6a6931127145d2ce4106eae3f0e588ed0e6a1c24d015d595640fe427ebb5753e1955ea8cfeca3dd0638b8e0b
+    a2dc9d2ee323e912007d462871314715;
+  94c18b5337685a96ed65b9ac
+    a338527ef19b09c063
+    c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e
+    7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d079839180
+    1691f3064921baaa57137b92ce00739789fad53203a0c5c0683cad9da5e2a54c15b6ea69870a807b40fa2006fd631f790f43a88a86
+    d5f6f01586bd510672cd9f062d846013;
+  5da08da3aefc5f85
+    84b7c5e617669c0f16e398
+    ""
+    ""
+    ""
+    7104d66a;
+  15d4e9cfce3ed1ec
+    df3d264a7f16cb16c2e815
+    f4
+    ""
+    ""
+    d82c0d6e;
+  22cdf0c8e30308be
+    3c31e6bc58c0b7cadcb658
+    ""
+    b9
+    a6
+    cb4b7117;
+  70e47479a684b5ae
+    fa69a4cd52147ed12c
+    a986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae98
+    5511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608
+    4763b77f7a624a9d1453034bea8d9c5061a93708adf6badc0e7372623212c427f6539c36f053398d051510adee65048f
+    79884b4232ec8611c3e862865e3d60ec;
+  fe95e81c2533e31c
+    9c1a9851bc2810d858
+    cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a7
+    7456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0c
+    fdfefeef8313360ebe5d7c5448129278ab19acbb0625d7e0675ce22a334269067523466c1cbad10c0a8630ae2d94d3b9a38dfe3db0
+    2ba0749d5c88e7dde18a94a99bcc3b69;
+  ae9ce021a5f1fa4ffa91544485f1a1258b
+    2b9b8f0911e32d65cc1770
+    ""
+    ""
+    ""
+    be73551e;
+  a18cbfe6effd1ff6778554acf1270485b2
+    03a3c1c4c967c0a458cb94
+    8b
+    ""
+    ""
+    922ec10b;
+  dd409b687fa3a6827b480aa3a4c84cef64
+    f6c9b53bf8f957f4b03cf4
+    ""
+    3e
+    9e
+    ceadc769;
+  89957f9a3e8128f8743d16687b7bb8deb9
+    bd205b70e04c091d20
+    5cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397
+    abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107
+    882d1a8dcf897a5fd0b0a23aed8016eb4ba2290f47c51ffbb244fd10614dc98bdd072c8dd2607ccb0a8509c13141fc03
+    541f7a6fcf2c319c9bdf291490aabd96;
+  c8e7d715a92add9589d1f5c054b2d98351
+    4605ec590294a319b9
+    802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee
+    1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44
+    87aacdd16e3d3bcd52d8bbbe6226bd5b405fd7ec9d93334a5ca599dfa600927a1270c54700d1d7ceb1fe25a033321359e98889bf74
+    9c7c6db5629007318783e4fadc1f1d67;
+}
+
+cast256-eax {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    2b961641462baf0a23af6720a9197d0a;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    c27ec7e5c6e5b2c0722a835e433f5708;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    91ee71af24a201bdc7dba1596261eced;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    36
+    21caca7994e9579e303e7c24be9fdb7f;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9
+    f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7
+    080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61
+    242810649692db21e7595173fad46df3f55019d4e719ceb5bc09a733997fcacc846e6ec1e0589e4c9e5355dfaace122f
+    4039884385c992be1a778520915dc0d6;
+  cdbda3b3e9878731ebfedd4705
+    e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    6536f3d0bd3929eb609818c1cee5e2be47a1a02f0f883c34867f9966cfe97a31b2fd4c821c520e1be3d0a736dd1661b6190e24c1a6
+    33856bece05f1ca8fe19b530e407b966;
+  5faee2b03fb648e27fff6310
+    ""
+    ""
+    ""
+    ""
+    ee2162ee6e8410aa5200171d0c4024aa;
+  2758fe2b69ac26afa3349829
+    b9
+    ""
+    ""
+    ""
+    87a91471cda81dd33d9b42545c8b0b8c;
+  4586306fed54154f8f28523c
+    ""
+    03
+    ""
+    ""
+    0e5e8f75620078311d835458946c93ff;
+  d4de1600157846b710ee7280
+    ""
+    ""
+    7a
+    a6
+    18d59976b1087c9b1790cc5e6b29d3ff;
+  2219bfb474fd71d891f24bb6
+    5d1563259f9eb53b571ea629c54d57dd
+    2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222
+    bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836813111
+    303058fd583dbf8ab83aff89f31060650b03148c7330a6be6858eb1d384bac97798c4211f919b1170b2c1ce6d3d8b0da
+    60ec12a7a132b714707aa1bfca3f3d67;
+  5c037ba323fe1dc815178487
+    3f0eb5b647da6794c18b5337685a96
+    ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89
+    d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d
+    efd6f1f344975f001595f2d1e3254791c4f1054f4e0932a85a28c1296308bad1c38aa7c2b2be16f2b14b94de98ce44d0255979ed5f
+    335688afe647757a98f871ebf99933b7;
+  30ce2f1fef6ef315
+    ""
+    ""
+    ""
+    ""
+    57a1e64ab9765509b8abd4c36b616844;
+  d0798391805da08d
+    a3
+    ""
+    ""
+    ""
+    9b3d0bae4a9f3fc0cc4135d73b6471e7;
+  aefc5f8584b7c5e6
+    ""
+    17
+    ""
+    ""
+    7a3a4fd12ec71c3058d3edc4416d6e56;
+  669c0f16e39815d4
+    ""
+    ""
+    e9
+    31
+    f15c15c0e14893b05d599ec77547c893;
+  cfce3ed1ecdf3d26
+    4a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98
+    ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b009
+    dab10d1acc2f9596d131f83d22dfcb5f76e3133ae715429bb9ae30c6c41b4035ea2ba2e6d2b7afd41ffb821b88b0f11b
+    2b770827aad8b1bfdf838506622ea7d6;
+  51f284649016ed00
+    456331854bc78bf43966eb0cfa9138
+    ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb82
+    4173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc5
+    180b3ae40e896c401aa0ec3a9323a97b3063486d3016f504ba931948fe5f48455bee3defdcec5d43d2e5b96f021f45027bf304c4a7
+    36388109db5182725e7dc0c9e8c18e18;
+  97f56ccbb2f294b38766fc69f6a9f2c094
+    ""
+    ""
+    ""
+    ""
+    65d71bd58e0cfc24609eb320f26c4144;
+  5ffd505003cc0cae9ce021a5f1fa4ffa91
+    54
+    ""
+    ""
+    ""
+    5c3f108cadaeed7fdc40c74003074e4a;
+  4485f1a1258b2b9b8f0911e32d65cc1770
+    ""
+    a1
+    ""
+    ""
+    deb0b205c88084de69e4dcd20f94372f;
+  8cbfe6effd1ff6778554acf1270485b203
+    ""
+    ""
+    a3
+    7d
+    e854cf62bc9c693207ab3c89432f5418;
+  c1c4c967c0a458cb948bdd409b687fa3a6
+    827b480aa3a4c84cef64f6c9b53bf8f9
+    57f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac
+    8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef340153
+    c8b37bf62703385c9441e1cdf357875ee437a15798e10c0717aefa605227bfffe401cfc610ae0b51d9f63e8098cc45bd
+    4e68c56bb64b3d6ac08e35248a671884;
+  9c51d2a90bbf7f1bfc338ab0ef5746ea8f
+    dcccd213e33f7e8a5718fd25014107
+    c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7
+    ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7ab
+    3afadb7496af2b3d618391fb535d6c6b42cb20a259c0f2d359d83055062b3f3c8715fbe13fe3b001c254ded295b2225e461ce11d2c
+    77dafdf4ffbffd0bafdc4b2a1c2a77f8;
+}
+
+cast256-gcm {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    e40bb3203b443cbb894937a4f69e6b67;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    e9c2fa823e33d9aac0cdff0f79008a96;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    c458bc5a2b89690b93e7d4603d8dc6c5;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    f3
+    a32741ffd61b5bb53b79a7df1e2e849f;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9
+    f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7
+    080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61
+    e8b2a245b1b44140bfde7f135603a3f4c088770181f486cee855087f0468fba9e4af3194c57ae401fd5304b6aca87204
+    7ba17b157ad26810dcc34b7a04b11a38;
+  cdbda3b3e9878731ebfedd4705
+    e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    e635fd965a15d413b93196514d7a577123025a4559f16734464afea880e538b0193db7477e52720ce3554332f406382cec81b57972
+    c6fcab0d8311749afdfc54ff38f4484d;
+  5faee2b03fb648e27fff6310
+    ""
+    ""
+    ""
+    ""
+    96bb8800b41ff193d4b4c65f59d19dde;
+  2758fe2b69ac26afa3349829
+    b9
+    ""
+    ""
+    ""
+    0318bc05a63c0e2dc859b0f13dad85ae;
+  4586306fed54154f8f28523c
+    ""
+    03
+    ""
+    ""
+    920fc4cab40ad51c11726fcb45c817ce;
+  d4de1600157846b710ee7280
+    ""
+    ""
+    7a
+    f6
+    947c572753bab643d56dd4095074acb1;
+  2219bfb474fd71d891f24bb6
+    5d1563259f9eb53b571ea629c54d57dd
+    2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222
+    bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836813111
+    c663c80f1a24265a81261cf9ae9b38ea937ddc6a3662815341fb9677608d8a1ed64d70bea85fed028af8f56563d9a8c6
+    989401a20cf7eafc84c597493b6ad0a2;
+  5c037ba323fe1dc815178487
+    3f0eb5b647da6794c18b5337685a96
+    ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89
+    d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d
+    fbc42f92cbccbe0dcc288a2781c8b0156a3ca42294cda5f5ba134558d63dfc445e57c58f5a262dba7c4fe923071a49006b0df6c76c
+    27f0a0861ef2ce9d671123efa0f6bc26;
+  30ce2f1fef6ef315
+    ""
+    ""
+    ""
+    ""
+    50e8f074272cc9a5a63212e7902d5df5;
+  d0798391805da08d
+    a3
+    ""
+    ""
+    ""
+    16203fda45ef8d1249caf3413f1718fc;
+  aefc5f8584b7c5e6
+    ""
+    17
+    ""
+    ""
+    fe964dc3fd7220defc4b718b74e1bcfb;
+  669c0f16e39815d4
+    ""
+    ""
+    e9
+    8f
+    07b2a554d209d7f24549dceb24015bf2;
+  cfce3ed1ecdf3d26
+    4a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98
+    ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b009
+    1f97c51ad029f02dbebe7fd0faa41da5d523bf06055b9c13188549427c2b41f689be95c2a53dcd73a5497fbcd32b664d
+    88fffe54f9bedb25fb5cd22f4d78b442;
+  51f284649016ed00
+    456331854bc78bf43966eb0cfa9138
+    ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb82
+    4173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc5
+    45170813ffb0c86e1d49c82c83b82d72ea126dbc788c27ec00b79ed4b266cbc66f9ef2311fb2c2464d1b81372dd120656250c427d0
+    736070378d728b22d9844d97bde5e22e;
+  97f56ccbb2f294b38766fc69f6a9f2c094
+    ""
+    ""
+    ""
+    ""
+    7323880f89fb54d552c1a23505f238fb;
+  5ffd505003cc0cae9ce021a5f1fa4ffa91
+    54
+    ""
+    ""
+    ""
+    bbd60af0b8d37b6a322ab217d1d9cdc9;
+  4485f1a1258b2b9b8f0911e32d65cc1770
+    ""
+    a1
+    ""
+    ""
+    829cc05afc938051344df29091d390d6;
+  8cbfe6effd1ff6778554acf1270485b203
+    ""
+    ""
+    a3
+    5d
+    e3c0d0132c0bb48fe0424f4c72b763e8;
+  c1c4c967c0a458cb948bdd409b687fa3a6
+    827b480aa3a4c84cef64f6c9b53bf8f9
+    57f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac
+    8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef340153
+    59516d118aa9a72775326beb658de1e0cfb0cda583731d1d69b0b47d0b0cd441844618383dca21b165b19a0c11dec493
+    ae577e6433b84bef607dc9e0fcb9403a;
+  9c51d2a90bbf7f1bfc338ab0ef5746ea8f
+    dcccd213e33f7e8a5718fd25014107
+    c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7
+    ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7ab
+    992b8af618edee3cfc8554dff63c15cb2767f995be01271c2cfd8fd552ba9736e3b40674bd386359c6ad649bd6ec0259891bdfdfcd
+    b50c46ca1142d5d4c72930495fa48515;
+}
+
+cast256-ocb1 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26d0c6
+    ""
+    ""
+    ""
+    f4e4aa5505f37af61a5a972c9fddc162;
+  eb14ad568f86edd1dc9268eeee
+    533285a6ed810c9b689daaa9060d2d4b
+    60
+    ""
+    ""
+    584463e75d3ac1157672be951d0055a0;
+  03062365b0a54364c76c160f11
+    896c4794846ecfa14a7130c9f1371206
+    ""
+    34
+    5c
+    b394bb4ab2b10e6e8cf2367e54a31532;
+  c9519848a877ff77bf79192a5b
+    50ade5d9cd739a3d1f337f29549e6b0d
+    ""
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    5e5c6671bcd32b508fcdf1290a9270f30ac874189f9e647431527ad1e4ff12bd82060a376c2668bbaa4716e80bbc9884
+    baeb21b394d13ec32b91057c7bf09405;
+  6057acc87638f508046733d9ff
+    61cdbda3b3e9878731ebfedd4705e505
+    da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5f
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54
+    04f1f1082ac15c13cce9ec3c1fcbe8691ac8c736973073538f54a2cbc387064256e8add5a710c2102f0230773d54e1a7
+    6e9c01e8e1cb63e1e545a84f84280577;
+  efc9a38378c5b93bf4f2aad260
+    5faee2b03fb648e27fff63102758fe2b
+    ""
+    69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9e
+    ffd476af7d1a5f68a96ecdfb466048936ba4d8c91e81057b23305c0d3120a0f30bfa23abcb7d3497912ceb161471933582a715b3ab
+    1d3aa8cb71b538852d3e674e5bf3615d;
+  b53b571ea629c54d57dd2d42f7
+    0800df9fcbaca48b77dba189196d1ebb
+    a10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b
+    0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da67
+    4d82601ad1a7e07573bed65ed8da86942029c74dc50df0e0f80b00bf3745f4266652f1e017340a07e94f96333f3333d61d0d940e5a
+    34184bf2c44520892ed7e493d2af584a;
+  94c18b5337685a96ed65b9ac
+    a338527ef19b09c063c46f88de9fd41e
+    ""
+    ""
+    ""
+    09b578e0b6e9577963d2995dcd8f0bd5;
+  72d7b97e23e6eabdff3bcd21
+    1499268878dbf30f1dad89d4b9b12012
+    e4
+    ""
+    ""
+    80b1ce3d1a2d08a260dcffd4a9f16abf;
+  713df46795630e7952d22bb0
+    2d7100b8b649377d20a8f083455b663e
+    ""
+    4e
+    ce
+    afd445d169a181a0d3ab494c21e853e0;
+  e1315f3c8f2aebfa921451dc
+    d1af5813b70d30ce2f1fef6ef315d079
+    ""
+    8391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e303
+    4e1f0bbef82b78b779df16313c391c02bd6f7345ce682a14b23b2abb89a2096e54a1de1109e918c370716ebdc875b2d4
+    dffb8a8a04a9255086211180d478d1b7;
+  08be3c31e6bc58c0b7cadcb6
+    58b970e47479a684b5aefa69a4cd5214
+    7ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9
+    f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908
+    499f455e969ad8bc52698430481a1c43a6cb786edb33fcde2407be7a18c6477d35d59eee05c523f870918e68500b78cd
+    0d448fdf7f32a1b4ea521a182677dd36;
+  445608fe95e81c2533e31c9c
+    1a9851bc2810d858cbbc8424d126b807
+    ""
+    e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3f
+    5d96f90a43251e531c7932bb2bd9b281f8281589ba1c490ddf3c57a32516eba4bd0eb418af024566da98156a0f83def4b51b2bb90f
+    43fecf4cb095b89844141707fd0d2643;
+  b90e1721b730374ffc9bc597
+    f56ccbb2f294b38766fc69f6a9f2c094
+    5ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6
+    778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f
+    ca44fbee713e258d9aea6a41b419530669e861a4c0beadc5653841d50680ab7fed4ad201ed83833d26e8afa66b8a91173eae53bc59
+    82a696e7b8a54d2cbdceedfae2d7182b;
+  9a3e8128f8743d16
+    687b7bb8deb9bd205b70e04c091d205c
+    ""
+    ""
+    ""
+    d92ad5b9acbcf8fb954dbb262344b172;
+  dad9e9a79b1abf91
+    b0851e5ca605ac845139958701167750
+    8a
+    ""
+    ""
+    e5e0cdba48ea323b69c3fd7873c61ac8;
+  15dde524af3e2bee
+    0646541a42c2ecccb44d65bad397abfa
+    ""
+    f5
+    29
+    989ebeaeb57f545955d5c2b8a76a5457;
+  29ee41cf9a05c7ef
+    edef3401539c51d2a90bbf7f1bfc338a
+    ""
+    b0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b980
+    f5017b00265a7b059589fe8549cd0d622805099dcf5d466a35dff3c0acbf40c1116ca692ec2388ec1fdbffdbfcc727f1
+    e00724826deae7efecaff58c6ff8dc4f;
+  2068a9f891bc5ba5
+    afabf8c3122d12d7ff3c41122d70d17d
+    4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68
+    daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9
+    38e8e939b456444e7a6dd8dd56c53376dfa8896e37a9cd10b16c5a5a2daa0ee885a2d3df7925fe71b8ad09d35e722a8c
+    81f8c645830a84009214a06300fc2feb;
+  aea3ccf860b00097
+    40763d96836c5f87b95460938de1288c
+    ""
+    69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308b
+    a7e718049be63223f6fcf229b7f907650bf6e10e8f53425f395df8b8aedf0658b001e1b1e717e75ba1b3750c9fa03714dbc5efeffa
+    e9fb84545896f7a672652dab4176b86b;
+  a60076817523bd2a
+    bf1261b089d8f23a9c2835076a23faac
+    2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa
+    8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578
+    e8f501b22016ada9cbfef68407a289863b7d3880603c3da8ea796352253441971cdd0171e8b57dcb32c58a078d439d523f36e17889
+    2b2a2e481234b511a0fee70c0924f67c;
+  c8ec4837898a92142b5b0677da1ac27311
+    7b45bcfff5d5f8b6fde2893232a9f81d
+    ""
+    ""
+    ""
+    c1cab79fe94cbf28ab64b07b34396c84;
+  14517ffae475f6b94a43a67b3d380d2f9a
+    aafe2dd721c0095c8808847689211450
+    ba
+    ""
+    ""
+    743df0e8509186cfb6ce313315f591df;
+  8095ffab1eaadf66fd22ac1976063e113a
+    b61f813e28a1397a7974a1d7f4220c78
+    ""
+    5f
+    26
+    503f2efabf0d67ef1e3ad58f79d6f17d;
+  e426a5a0e80f678d404147842941feeffd
+    c2eb44dc8c0d5e8f444f7f4e0c893959
+    ""
+    b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3
+    1e06a0e13fc9f0db0a30711b19af2ec7eaa3927ec5338711ceb30b6610c76e473b7a3668ece81dc0f73253a516413982
+    53954399118d5578d98e208d426b0366;
+  ab6cf8556b7aa776945948d1b8834df219
+    6c92ec1718dcdeee0d52d9539726d281
+    0391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa
+    4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0
+    a4d6895902d47c9ef748ad8517e2d12561e2c068f16250af0fed5f2e2ae5afbd7f207ba0511039c9ae5562d230a2fac4
+    1ead7569ca82cb5cfd6b06fe6956c91e;
+  a9aabb6c4e3c3554f8fb1ef61614c27029
+    5dfc0ca6551ca4bdb75359f91cb9d921
+    ""
+    056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3d
+    0a97b9588a0aff4d72af4e22c74f318a40355d94e0e0b200a0f8d06d5bd9d54728665f613e0bba43618f384303c3332e7bb746ec9c
+    99bb95cd33b76350d1b7de4543001f0e;
+  f6c2b3fac7cbcf96523d4723f91801325e
+    b8553236651c96788d73d192ee53b3f3
+    ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837
+    bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b5
+    a3a36df6117ba70650188e6b240237f97b545f08ad010f9eff2cc0a7ced297c38c495ac0f293cd4a6d9f56d96e31b17f64c7bcf949
+    6bab5e7330a0c1f6a651f0a33e17327f;
+}
+
+cast256-pmac1 {
+  60d7bcda163547d348b7551195
+    ""
+    e8bbe6976040b637c5730cead91a9243;
+  e77022907dd1dff7dac5c9941d
+    26
+    afcd96681e4a0ed5af47bb8b17d41497;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    b584d84fe844382627cede2f7c6e5299;
+  34c9519848a877ff77bf79192a
+    5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    b232cc4c44afe1700f942c996e05e589;
+  8374d8cde8e160ad10997a21
+    ""
+    f0389f03e4cfb0f88b4016b8a96703bb;
+  635c6d62c9269029df3e6057
+    ac
+    754f863997eb465cc5ada5e2febd22a7;
+  c87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    407841bdebb8eb02d282ef5890f76dbf;
+  21b7f65b000961040ef2f9b2
+    fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    0ee25678e76d4bfd0bd892417f3a4aeb;
+  4215abd6b3ad54ef
+    ""
+    d31ba003e87b06c6f0eb3c9e93090855;
+  c9a38378c5b93bf4
+    f2
+    cd4ec1c2080823a36b6a223b15c6f9db;
+  aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    8c621081c3ad80573f0003d5ed7b7ca8;
+  bfb474fd71d891f2
+    4bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9f
+    a61047ab500558a62e494702a55f0426;
+  c2712a199e533fa9156308cdec3f768281
+    ""
+    d7db14580abbffd94087bd893c44bb9c;
+  e040a9b9a222bd689aef66f5306ceb0c6b
+    08
+    f30bab211ce253887d48d7788411a8fd;
+  ac8b0a22260c571b4a42bb8fdb233bfa6a
+    5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    e7cb4245e3ce926311a964eaff43f853;
+  b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    37e48b490fc5476f6a317210987af58c;
+}
+
+cast256-ocb3 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26
+    ""
+    ""
+    ""
+    5d4fdb3278da8699e7a297755690b588;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9
+    06
+    ""
+    ""
+    fd23cef36d5d13dfbbc3f91a2edcbed2;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a71
+    ""
+    30
+    c1
+    5890dc2ce6ae75f9c7072f3c06cc6aac;
+  c9f137120634c9519848a877ff
+    77bf79192a5b50ade5d9cd
+    ""
+    739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    ba75fc237e106f6352333d944d8a6a0f8bfe641cf9242e343a63b4d591c2cdc18a6c50c88580b23e045876e62431d6d1
+    e9af104923e66478d2bbac836c025af7;
+  21635c6d62c9269029df3e6057
+    acc87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    21b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a480
+    856379775dd26a3b347f1e25434238aabccfbd70ecabff489dafd8d2d25fe86ae4cf09bd85f2c739f0365c4e7afb4bee
+    a43529bee26dd2393a369de5d2e23a55;
+  30370c33d090c54215abd6b3ad
+    54efc9a38378c5b93bf4f2aad260
+    ""
+    5faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    60e28a1e146d789fa2b63320cfd0dbb8de71aad2d5f2df5200a8c179db39e2a64e8f7bc0926ac95fc11a65cbd36935bc03c8b13dca
+    3666a5ec5c24466c0680e3d6062b30fd;
+  bfb474fd71d891f24bb65d1563
+    259f9eb53b571ea629c54d57dd2d
+    42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040
+    a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c
+    513e8a344d74844ef67effb6805688174ea7685fd8ba3a2860cd98864c5bcc699b69fe97963dcfbcda987b28e4d649ca5d45378a13
+    6259e08c9387922cf33a2e5b86c23e38;
+  037ba323fe1dc8151784873f
+    0eb5b647da6794c18b5337685a96
+    ""
+    ""
+    ""
+    cfafee3e2ee7315fefeac9f823d4ec1e;
+  ed65b9aca338527ef19b09c0
+    63c46f88de9fd41e72d7b97e23e6
+    ea
+    ""
+    ""
+    8fd186584d18210cb316f19fea0bd516;
+  bdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012e4713df467
+    ""
+    95
+    33
+    d846c750ec238730ef2611b41ef1d22f;
+  630e7952d22bb02d7100b8b6
+    49377d20a8f083455b663e
+    ""
+    4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f
+    66e0593cdc31156b9cca5bbce514957973bd0186966333560fbc521e413fb7b3ce7189751f51708bf4424cca548a00b0
+    e4f02aebcee994443b0f438fd0d5e917;
+  16e39815d4e9cfce3ed1ecdf
+    3d264a7f16cb16c2e815f422cd
+    f0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4f
+    cb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb
+    d182ac26587fc4ea051ef5e86830194d4f6afe030b7a72355dfc307eefffb85fc972a9e0ec73e25db66d4e98d8d7eb9d
+    3905dfc881ebf47d63219f7a3824c03c;
+  1c8dd0b00951f284649016ed
+    00456331854bc78bf43966eb0cfa
+    ""
+    9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f
+    fac401c9710f7a1adf621eef0169fd85bb9efd3e5a2a59f2d985c72665c3fe1043563eee9bcfe24902ea2a20565ee073c556c0897d
+    ea51bd57dadb6f1b4aa5b85471a9b725;
+  30cbb7f0e4a973a8cd190107
+    314717a77456f3ff669c732b58db
+    8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0c
+    ae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a4
+    7f34458b9f7bdb1075bd95a6577649bc50bbfedeedb3eaadad5610c87416621c2496fb61c94ad5ac6d1d157556260ed4ee9762c5df
+    4e98bd96daadb7ba8885c55080fd944f;
+  58cb948bdd409b68
+    7fa3a6827b480aa3a4c84cef64f6
+    ""
+    ""
+    ""
+    54a6dca9e4f6b456ca9a72d5430bf37f;
+  c9b53bf8f957f4b0
+    3cf43e89957f9a3e8128f8743d16
+    68
+    ""
+    ""
+    680d5049038160aeee6c7a4a3030990d;
+  7b7bb8deb9bd205b
+    70e04c091d205cdad9e9a79b1abf
+    ""
+    91
+    c0
+    3cf99a9f061f858ef7e0fb11d7f16467;
+  b0851e5ca605ac84
+    51399587011677508a15dd
+    ""
+    e524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0
+    f364b814e500ef9ab50b1f0c5cc2bddd2c00e7622f85716506453739fbb85ebd7c9c5d6bb06e1ac7974b640bab4fb2e2
+    538fef69d96b24725f40d036b7b6664e;
+  ef5746ea8fdcccd2
+    13e33f7e8a5718fd25014107c8
+    e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70
+    d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8
+    4f968a35e00430a894fa0af39d8e46cbf5f6df56646d148532800533bc976923e4d9228a11def3ff976c6be7ccead573
+    9722d670c7a13c44d3fb8e0e97446166;
+  ad68daac90cfe22d
+    2f1f2968cc42fa8b669ed3bb3542
+    ""
+    a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69
+    237f19a52651cdcd603091b3ca1b5d7a3131761987c0f38664d0432917123bbee65ccaa962fdee1431aa26d2f247e05df2017a6f73
+    002e125c7224c549106c0c0f82d731ed;
+  d80ea12ff4bb5f06
+    9b8a2e86041c1b9fc214e9ca2186
+    ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089
+    d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4
+    2094d61a83dedbd274dee89488d255879775fff59a5dcd4c270e2adab6e0d4ed7b48e867cd45400d77a667104d6a35a0056b5b9abe
+    dce0b2e1f5ba9e73aaff6246e384cbfe;
+  fa8fec816ac861a8b33779f09e7a10fc02
+    a8f48afa3080ee119a52a9a817e4
+    ""
+    ""
+    ""
+    6dea6ebbce273e40bf6b5ba1481560d5;
+  f2b94b0820cab383a8cffeea7c48631579
+    9dc875fba578c8ec4837898a9214
+    2b
+    ""
+    ""
+    ef480ec30616d41fb86f4f79858304ca;
+  5b0677da1ac273117b45bcfff5d5f8b6fd
+    e2893232a9f81d14517ffae475f6
+    ""
+    b9
+    77
+    8af99e141e67210c5239e5d4f6016e59;
+  4a43a67b3d380d2f9aaafe2dd721c0095c
+    8808847689211450ba8095
+    ""
+    ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feef
+    b0315e2ce88fdc82212d14ff369becee4cc30d1e591bc73e9cb807b5014e50d2a03b416ccf7e403d0c788000d752c544
+    565bb827571e2d4746ea15001c3a511c;
+  fdc2eb44dc8c0d5e8f444f7f4e0c893959
+    b74dc23a7bb40e7e0013e51506
+    86d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8
+    834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e73
+    6882d9145b766d004aa23db26e6727b910a52b3524cf41e5b079063a5690876e00b8446bd49b8fe0f96c646a9de22fd0
+    e1478799571f8ad2f2376901b4d0f0ba;
+  7882cd09c2b9a80f34c0fde11c2481b11f
+    c76bfa4dbf710a9e544e0c536ca1
+    ""
+    e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270
+    9bfd938b0ddf7d005d20bab1060d8fae70cf3b084df0d31b76aeb0356f191bd9dd16f2a0ac6a6b4c910a7bb5982dc5ff5b7e99bf3a
+    3fbd1c0a5b88616249b56c90758cdb29;
+  295dfc0ca6551ca4bdb75359f91cb9d921
+    056b7de74fc9a9b37154ce6c0b39
+    6179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fa
+    c7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b5
+    a58bb37e7d47cb624edd3d81393569f1b6dfe1cc7e50af93187a22abdef670f81e2ec2e0ddbc5a4fce6f61bfd15e642128305d6026
+    95512397bf2fdd2cb6111fd1763fe66b;
+}
+
+cast256-ocb3-mct {
+  32 620ecceaf099c7d1772580169dbe93a0;
+  28 95fc3dcdf6e2582e821ad38cd6c26391;
+  24 acef03ad345af5000cb5ef196bd366b7;
+  20 0f1a6f49f6853abb75ce4e90c58599ea;
+  16 4258d565f5ec42869802cd5cd5d21a96;
+  12 f8fc10048890fb153d71d846be4ce8ed;
+  10 aaab0bbcaa81d7b3b5b1269a3761335e;
+   8 329c9f836301b423469a56ad770da468;
+   4 68fc11ed2e38d35ba5bf89af2c9f856c;
+  32 c0310249248a38ff9950a833;
+  28 b97c775bf1d0c8ef8284fee6;
+  24 67a579e69bf507321be80304;
+  20 7077b0ec786e90698b31f028;
+  16 f326d6be1d1c2758e6bc69b1;
+  12 8f3110db5963f2e800f22f06;
+  10 58a1c2500f16812836519b52;
+   8 3d0e35b1e0cb21f08410d22f;
+   4 6d9f16f675839f35d0a9bf7d;
+  32 af8a0e5cd2075f9c;
+  28 9610c921db423fd5;
+  24 e228f80e94e1fe31;
+  20 a7a0f74679eb7543;
+  16 b64ea6aa7a4d2c86;
+  12 695dda9261b41e4f;
+  10 27064d4c545536b5;
+   8 1868f259d6049ec2;
+   4 fc3fd6f530c8c94e;
+}
index 043397a..c771554 100644 (file)
@@ -31,12 +31,19 @@ chacha8-core {
 
 xchacha20 {
   ## Unfortunately, XChaCha isn't actually defined anywhere, even though it's
-  ## obvious how to do it.  These test vectors are from
-  ##   https://github.com/DaGenix/rust-crypto/blob/master/src/chacha20.rs
+  ## obvious how to do it.
 
+  ## These test vectors are from
+  ##   https://github.com/DaGenix/rust-crypto/blob/master/src/chacha20.rs
   1b27556473e985d462cd51197a9a46c76009549eac6474f206c4ee0844f68389
   69696ee955b62b73cd62bda875fc73d68219e0036b7a0b37 "" 0 ""
   4febf2fe4b359c508dc5e8b5980c88e38946d8f18f313465c862a08782648248018dacdcb904178853a46dca3a0eaaee747cba97434eaffad58fea8222047e0de6c3a6775106e0331ad714d2f27a55641340a1f1dd9f94532e68cb241cbdd150970d14e05c5b173193fb14f51c41f393835bf7f416a7e0bba81ffb8b13af0e21691d7ecec93b75e6e4183a;
+
+  ## This one's from draft-irtf-cfrg-xchacha-03.
+  808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
+  404142434445464748494a4b4c4d4e4f5051525354555658 "" 64
+  5468652064686f6c65202870726f6e6f756e6365642022646f6c65222920697320616c736f206b6e6f776e2061732074686520417369617469632077696c6420646f672c2072656420646f672c20616e642077686973746c696e6720646f672e2049742069732061626f7574207468652073697a65206f662061204765726d616e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c757369766520616e6420736b696c6c6564206a756d70657220697320636c6173736966696564207769746820776f6c7665732c20636f796f7465732c206a61636b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d69632066616d696c792043616e696461652e
+  7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee053a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd20112f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63d595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4d0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d316838a9c71f70b5b5907a66f7ea49aadc409;
 }
 
 chacha8 {
@@ -229,3 +236,21 @@ chacha20 {
   000000000000000000000002 "" 0 ""
   965e3bc6f9ec7ed9560808f4d229f94b137ff275ca9b3fcbdd59deaad23310ae;
 }
+
+chacha20-poly1305 {
+  ## Test from RFC7539.
+  808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
+    070000004041424344454647
+    50515253c0c1c2c3c4c5c6c7
+    4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e
+    d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116
+    1ae10b594f09e26a7e902ecbd0600691;
+
+  ## Test from draft-irtf-cfrg-xchacha-03.
+  808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
+    404142434445464748494a4b4c4d4e4f5051525354555657
+    50515253c0c1c2c3c4c5c6c7
+    4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e
+    bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b4522f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff921f9664c97637da9768812f615c68b13b52e
+    c0875924c1c7987947deafd8780acf49;
+}
index 7b75304..8b3edb2 100644 (file)
@@ -60,3 +60,465 @@ des {
 
   0e329232ea6d0d73 8787878787878787 0000000000000000;
 }
+
+des-cmac {
+  bef260d7bcda1635
+    ""
+    38adff25bb9e255b;
+  47d348b7551195e7
+    70
+    a70403c9dc15813e;
+  22907dd1dff7dac5
+    c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed
+    5e05047524a92169;
+  810c9b689daaa906
+    0d2d4b6003062365b0a54364c76c160f11896c
+    d345f04671d2f856;
+  4794846ecfa14a
+    ""
+    d1f159eb76e2dcb3;
+  7130c9f1371206
+    34
+    1728ecf20653375b;
+  c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4
+    6f19d2ec30d3057a;
+  ba234085406a61
+    36512061f7080cc07df0591d8fa21f2dd88374
+    2b5a2cec413de519;
+}
+
+des-ccm {
+  bef260d7bcda1635
+    47d348
+    ""
+    ""
+    ""
+    97684266;
+  b7551195e7702290
+    7dd1df
+    f7
+    ""
+    ""
+    46cb911b;
+  dac5c9941d26d0c6
+    eb14ad
+    ""
+    56
+    da
+    952bf9f2;
+  8f86edd1dc9268ee
+    ee533285a6
+    ed810c9b689daaa9060d2d4b6003062365b0a54364c76c16
+    0f11896c4794846ecfa14a7130c9f137120634c9519848a8
+    cfdc3c0afd5fdd440f0e1898cb7cc518539e54d77a406117
+    2c49a88b22b8108b;
+  77ff77bf79192a5b
+    50ade5d9cd
+    739a3d1f337f29549e6b0d27a4ba234085406a
+    6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    fcd66aee455ff8c114978554c7a9debc11b642cff67c13f54f43c84302
+    7c38973da8da2aec;
+  21635c6d62c926
+    9029df
+    ""
+    ""
+    ""
+    ce0d4ebc;
+  3e6057acc87638
+    f50804
+    67
+    ""
+    ""
+    3e4ba751;
+  33d9ff61cdbda3
+    b3e987
+    ""
+    87
+    41
+    2a565655;
+  31ebfedd4705e5
+    05da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a
+    e1eaaf9f5e53008063e0e21e064025aa423fb9a0a86996d0
+    e257ab7ac4bc8b67;
+  9b542cde52ebfd
+    a19d0ccc52
+    0f215eb57bb3a4f3ebbbb18ac6c95a97a48030
+    370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2
+    52f8b409665916709096ea1116886f51d56d6f48f3e0c298f8ded5d660
+    5d9404a726617d55;
+}
+
+des-eax {
+  bef260d7bcda1635
+    ""
+    ""
+    ""
+    ""
+    4fd7b7ceb605971d;
+  47d348b7551195e7
+    70
+    ""
+    ""
+    ""
+    362aa5d62008f0b2;
+  22907dd1dff7dac5
+    ""
+    c9
+    ""
+    ""
+    da21b21da7d57854;
+  941d26d0c6eb14ad
+    ""
+    ""
+    56
+    01
+    91d13047c75395e9;
+  8f86edd1dc9268ee
+    ee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f1189
+    6c4794846ecfa14a7130c9f137120634c9519848a877ff77
+    ff6584338c84f608f20f9b45387b79f759e4bbffdb97a914
+    a58397ff608476d2;
+  bf79192a5b50ade5
+    d9cd739a3d1f33
+    7f29549e6b0d27a4ba234085406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62
+    af4d58477434a67a527bd0abfbed0edc0e1d65db63ce387eee315f026a
+    e566a58b1afd6dde;
+  c9269029df3e60
+    ""
+    ""
+    ""
+    ""
+    ce840f6919760b2f;
+  57acc87638f508
+    04
+    ""
+    ""
+    ""
+    d2004b1898772d24;
+  6733d9ff61cdbd
+    ""
+    a3
+    ""
+    ""
+    7280bac984631a8b;
+  b3e9878731ebfe
+    ""
+    ""
+    dd
+    e8
+    75dd11b7cf5f0dae;
+  4705e505da1435
+    dceaa7b1cc49ae1d
+    50c38201a894476b3f102b752eb9529533966f27043eb621
+    b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfd
+    5cdd7720adf593db701494fc78e1bbd48e8fb79727cf09ad
+    b5c7ced07cae4060;
+  a19d0ccc520f21
+    5eb57bb3a4f3eb
+    bbb18ac6c95a97a48030370c33d090c54215ab
+    d6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff6310
+    df23153076ea552eabc472d40d9c4e859e707cb2acc2d8aa7e828b949b
+    01fcd2f2e30d870c;
+}
+
+des-gcm {
+  bef260d7bcda1635
+    ""
+    ""
+    ""
+    ""
+    b95298cbf804f0df;
+  47d348b7551195e7
+    70
+    ""
+    ""
+    ""
+    22c33c13d4284fda;
+  22907dd1dff7dac5
+    ""
+    c9
+    ""
+    ""
+    32e3e11e770712c8;
+  941d26d0c6eb14ad
+    ""
+    ""
+    56
+    fa
+    366c7284d32c1c2b;
+  8f86edd1dc9268ee
+    ee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f1189
+    6c4794846ecfa14a7130c9f137120634c9519848a877ff77
+    44f226038a81c0bf29f563401555ce1f15c8d35934f4757e
+    19590fc8720cd177;
+  bf79192a5b50ade5
+    d9cd739a
+    3d1f337f29549e6b0d27a4
+    ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10
+    4cf8117a588a98676db9fcbc8fd592fc8e065354683bdde62cbdaec0ba89ef9a7e
+    0ddf3556750fe18e;
+  997a21635c6d62c9
+    269029df3e6057
+    acc87638f508046733d9ff61cdbda3b3e98787
+    31ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f10
+    bd611ed6e68f3bb8ae3b8b3eccae4a26c64ee9febe4fd46797bf634545
+    5233b3b52edfd9b3;
+  2b752eb9529533
+    ""
+    ""
+    ""
+    ""
+    deb6bb8d0f98e479;
+  966f27043eb621
+    b7
+    ""
+    ""
+    ""
+    f72d871e2f82a356;
+  f65b000961040e
+    ""
+    f2
+    ""
+    ""
+    12e8da9a09fd309b;
+  f9b2fc5fa45072
+    ""
+    ""
+    7a
+    06
+    51a7355bf0814b08;
+  9b542cde52ebfd
+    a19d0ccc520f215e
+    b57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215
+    abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb6
+    4826d7b427e8d7dbfd700e8ef337210c86c2d5994781ebb0
+    19ab2b84d1b8165a;
+  48e27fff631027
+    58fe2b69
+    ac26afa3349829b9458630
+    6fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f2
+    43672e659b8698b44928111f7554e23e567bec8fd062387337d29a6f8332f563e3
+    c3ef31f3b831d4e9;
+  4bb65d1563259f
+    9eb53b571ea629
+    c54d57dd2d42f70800df9fcbaca48b77dba189
+    196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040
+    c34cf61443b0c83d4120ed5e4ffd2469382732dfb776bc2ce6771cfaf6
+    346dc157ce8660d5;
+}
+
+des-ocb1 {
+  bef260d7bcda1635
+    47d348b7551195e7
+    ""
+    ""
+    ""
+    1e777d9a35a9e879;
+  7022907dd1dff7da
+    c5c9941d26d0c6eb
+    14
+    ""
+    ""
+    90dff887c781b59b;
+  ad568f86edd1dc92
+    68eeee533285a6ed
+    ""
+    81
+    55
+    5c9be7f28d9f3021;
+  0c9b689daaa9060d
+    2d4b6003062365b0
+    ""
+    a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    98fabe1568fd4a31b60b6b90cc58dee9852314abdf9f4d89
+    32bf6f1f094d55d1;
+  34c9519848a877ff
+    77bf79192a5b50ad
+    e5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136
+    512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad
+    ec6d227abc440c6ece3ba42013676031c0fb2960d0d65985
+    485047e83b3b11af;
+  10997a21635c6d62
+    c9269029df3e6057
+    ""
+    acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da14
+    1b7100307ae4b3ca2e3f973e2ccd11be6245f9b081a36cc023801d9a8f
+    5e2e02663e595bc7;
+  35dceaa7b1cc49ae
+    1d50c38201a89447
+    6b3f102b752eb9529533966f27043eb621b7f6
+    5b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f21
+    23ba63682d64c1e2ed3c14de44c492cf82ac3c63b1e85ae1d5905c1577
+    a2786c37e5b03355;
+  5eb57bb3a4f3eb
+    bbb18ac6c95a97a4
+    ""
+    ""
+    ""
+    846708610518ffc4;
+  8030370c33d090
+    c54215abd6b3ad54
+    ef
+    ""
+    ""
+    152246d59c398d68;
+  c9a38378c5b93b
+    f4f2aad2605faee2
+    ""
+    b0
+    79
+    d74b0529249254f2;
+  3fb648e27fff63
+    102758fe2b69ac26
+    ""
+    afa3349829b94586306fed54154f8f28523c03d4de160015
+    90d6861b964eed693b629e01188d4e50fcd236e71ccdc734
+    0611bd11e7649655;
+  7846b710ee7280
+    7a2219bfb474fd71
+    d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f7
+    0800df9fcbaca48b77dba189196d1ebba10b0467cb9fc271
+    9fb915d584569a6bc699706d225c9f131bed57d39b7bb4e3
+    fdc4da4d6d428967;
+  2a199e533fa915
+    6308cdec3f768281
+    ""
+    e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb
+    78e88cc7c809ee0d77e4550e3ba943fa3390b0e035bb4569fff7bc58ce
+    821ba4f7ffd7cc02;
+  8fdb233bfa6a5c
+    fb0bad7d95214ade
+    49cb3b6f5fe8368131115c037ba323fe1dc815
+    1784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09
+    e6b1c822199a5821020dea58a059635e7ceaa997c3bf8338bade196e39
+    417dceee9a662328;
+}
+
+des-pmac1 {
+  bef260d7bcda1635
+    ""
+    87398f9b84eacbd3;
+  47d348b7551195e7
+    70
+    c4a6d220ebf7ce9e;
+  22907dd1dff7dac5
+    c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed
+    9847df50037cb1ba;
+  810c9b689daaa906
+    0d2d4b6003062365b0a54364c76c160f11896c
+    fe45499fb92b19ae;
+  4794846ecfa14a
+    ""
+    c7fc008258249c34;
+  7130c9f1371206
+    34
+    5d742a297938a8a1;
+  c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4
+    7cfba1467a3d156a;
+  ba234085406a61
+    36512061f7080cc07df0591d8fa21f2dd88374
+    0b547da65d93cc08;
+}
+
+des-ocb3 {
+  bef260d7bcda1635
+    47d348b75511
+    ""
+    ""
+    ""
+    4b59c22684f05b82;
+  95e77022907dd1df
+    f7dac5c9941d
+    26
+    ""
+    ""
+    4cd9eea7a5f450a6;
+  d0c6eb14ad568f86
+    edd1dc9268ee
+    ""
+    ee
+    d2
+    c2fd51cbecc7d7da;
+  533285a6ed810c9b
+    689daa
+    ""
+    a9060d2d4b6003062365b0a54364c76c160f11896c479484
+    5618b880cf7e0455afe09f1aa07e38de2eee04ffbba014a5
+    a22ffdfcd123b06f;
+  6ecfa14a7130c9f1
+    37120634c9
+    519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29
+    549e6b0d27a4ba234085406a6136512061f7080cc07df059
+    7198f4d67f9d7ccae66e114745dd13b874d837fde0b5260a
+    e35c2d0fc8291130;
+  1d8fa21f2dd88374
+    d8cde8e160ad
+    ""
+    10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cd
+    a71a247ba8ca953a41dabaabf6c2c6a88f5e83c466a18fd8fd7b7595b8
+    f00ab9e066d2b84b;
+  bda3b3e9878731eb
+    fedd4705e505
+    da1435dceaa7b1cc49ae1d50c38201a894476b
+    3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5f
+    ac3adc8ac7c662d73901110404b26e56622c2b0208a34517256ca0876b
+    a5bd20d0748afcc7;
+  a450727a9b542c
+    de52ebfda19d
+    ""
+    ""
+    ""
+    0fe8c6e02dfc921b;
+  0ccc520f215eb5
+    7bb3a4f3ebbb
+    b1
+    ""
+    ""
+    70f6e10b0765c5e5;
+  8ac6c95a97a480
+    30370c33d090
+    ""
+    c5
+    fc
+    e4a4438e74e98df5;
+  4215abd6b3ad54
+    efc9a3
+    ""
+    8378c5b93bf4f2aad2605faee2b03fb648e27fff63102758
+    659653c7ad91a79469d940fa2363013b939286f21cc49eee
+    f15e30c3bfe7697d;
+  fe2b69ac26afa3
+    349829b945
+    86306fed54154f8f28523c03d4de1600157846b710ee7280
+    7a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea6
+    ce4e983f478dbf2b09b3bad8af3dd6341645b8d4b492ff68
+    d1179f9268c3b779;
+  29c54d57dd2d42
+    f70800df9fcb
+    ""
+    aca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cd
+    d337d3fd33b17c42b364dc862e8b85f506e4f444ed7f63ed4440b65bf8
+    898fa93ba1e83b92;
+  ec3f768281e040
+    a9b9a222bd68
+    9aef66f5306ceb0c6b08ac8b0a22260c571b4a
+    42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c03
+    139b42f78a74486d2488d4de046e14b0b8d9c49efc78718b87d5f72697
+    8e529f719d87d2ee;
+}
+
+des-ocb3-mct {
+   8 d3d27b14989225a9;
+   7 eb3be38e3517c6d1;
+   8 70d5d3c75417;
+   7 93e83240fae6;
+   8 bdc8b8e1;
+   7 4407c007;
+}
index f1adb1a..afe7398 100644 (file)
@@ -39,3 +39,938 @@ des3 {
   0123456789abcdeffedcba987654321089abcdef01234567
        0123456789abcde7 de0b7c06ae5e0ed5;
 }
+
+des3-cmac {
+  ## Examples from NIST.
+
+  0123456789abcdef23456789abcdef01
+    ""
+    79ce52a7f786a960;
+  0123456789abcdef23456789abcdef01
+    6bc1bee22e409f96e93d7e117393172a
+    cc18a0b79af2413b;
+  0123456789abcdef23456789abcdef01
+    6bc1bee22e409f96e93d7e117393172aae2d8a57
+    c06d377ecd101969;
+  0123456789abcdef23456789abcdef01
+    6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
+    9cd33580f9b64dfb;
+
+  0123456789abcdef23456789abcdef01456789abcdef0123
+    ""
+    7db0d37df936c550;
+  0123456789abcdef23456789abcdef01456789abcdef0123
+    6bc1bee22e409f96e93d7e117393172a
+    30239cf1f52e6609;
+  0123456789abcdef23456789abcdef01456789abcdef0123
+    6bc1bee22e409f96e93d7e117393172aae2d8a57
+    6c9f3ee4923f6be2;
+  0123456789abcdef23456789abcdef01456789abcdef0123
+    6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
+    99429bd0bf7904e5;
+
+  ## Locally generated tests.
+  60d7bcda163547d348b7551195e7
+    ""
+    97b9dfb874462432;
+  7022907dd1dff7dac5c9941d26d0
+    c6
+    f403026117612b0e;
+  eb14ad568f86edd1dc9268eeee53
+    3285a6ed810c9b689daaa9060d2d4b6003062365b0a54364
+    4e0fbacfa297003b;
+  c76c160f11896c4794846ecfa14a
+    7130c9f137120634c9519848a877ff77bf7919
+    19d5f833e07e2015;
+  2a5b50ade5d9cd73
+    ""
+    ed38c0855386e014;
+  9a3d1f337f29549e
+    6b
+    c86e5386ee0e7b04;
+  0d27a4ba23408540
+    6a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8
+    d5306ab188df59b5;
+  e160ad10997a2163
+    5c6d62c9269029df3e6057acc87638f5080467
+    b6fc8dee2287152c;
+  33d9ff61cdbda3b3e9878731ebfedd47
+    ""
+    349cd58ebc44cb39;
+  05e505da1435dceaa7b1cc49ae1d50c3
+    82
+    a8322086e22dbed8;
+  01a894476b3f102b752eb9529533966f
+    27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b54
+    35c70f6e2cbab396;
+  2cde52ebfda19d0ccc520f215eb57bb3
+    a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    639e5e64b410da07;
+  4215abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    ""
+    41240c9c71435050;
+  aee2b03fb648e27fff63102758fe2b69ac26afa334
+    98
+    ab4c2c83747e8c5b;
+  29b94586306fed54154f8f28523c03d4de16001578
+    46b710ee72807a2219bfb474fd71d891f24bb65d1563259f
+    eff715a559241957;
+  9eb53b571ea629c54d57dd2d42f70800df9fcbaca4
+    8b77dba189196d1ebba10b0467cb9fc2712a19
+    2753a7135b48898f;
+}
+
+des3-ccm {
+  60d7bcda163547d348b7551195e7
+    702290
+    ""
+    ""
+    ""
+    aa48bfd6;
+  7dd1dff7dac5c9941d26d0c6eb14
+    ad568f
+    86
+    ""
+    ""
+    06de8798;
+  edd1dc9268eeee533285a6ed810c
+    9b689d
+    ""
+    aa
+    67
+    35d148d9;
+  a9060d2d4b6003062365b0a54364
+    c76c160f11
+    896c4794846ecfa14a7130c9f137120634c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4
+    a0cbf7ade835afc80d0244a41b72699e7f135479dcbf06f7
+    9d8fd60bbb5deed9;
+  ba234085406a6136512061f7080c
+    c07df0591d
+    8fa21f2dd88374d8cde8e160ad10997a21635c
+    6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e98787
+    09be940770a72970058ad3f06c973a2b58a7cc912892bc397eff73662e
+    9146a93e7398cddb;
+  31ebfedd4705e505
+    da1435
+    ""
+    ""
+    ""
+    92740192;
+  dceaa7b1cc49ae1d
+    50c382
+    01
+    ""
+    ""
+    d1803413;
+  a894476b3f102b75
+    2eb952
+    ""
+    95
+    63
+    c416162e;
+  33966f27043eb621
+    b7f65b0009
+    61040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc52
+    0f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090
+    b70fe9f3c530c75595207f22867614779980e9ada1c35be5
+    236101f21d127547;
+  c54215abd6b3ad54
+    efc9a38378
+    c5b93bf4f2aad2605faee2b03fb648e27fff63
+    102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de
+    ffc2c6c900f35a8d4c0bc244cf5ebff8f9999f4ce5759b39131585d376
+    9661947e6ea6d306;
+  1600157846b710ee72807a2219bfb474
+    fd71d8
+    ""
+    ""
+    ""
+    1afd62e9;
+  91f24bb65d1563259f9eb53b571ea629
+    c54d57
+    dd
+    ""
+    ""
+    9be5f1b8;
+  2d42f70800df9fcbaca48b77dba18919
+    6d1ebb
+    ""
+    a1
+    2f
+    8ec7e387;
+  0b0467cb9fc2712a199e533fa9156308
+    cdec3f7682
+    81e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a2226
+    0c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b
+    479741dd816d10d912b027aa913872636fc029c5b3b5e786
+    b52afd4780869038;
+  6f5fe8368131115c037ba323fe1dc815
+    1784873f0e
+    b5b647da6794c18b5337685a96ed65b9aca338
+    527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd21149926
+    2659d885994c1c74498d5caa2a19430c3622f508c1754794f736759134
+    1fd64bfce60b9b7c;
+  8878dbf30f1dad89d4b9b12012e4713df46795630e
+    7952d2
+    ""
+    ""
+    ""
+    cbf3fe95;
+  2bb02d7100b8b649377d20a8f083455b663e4ee131
+    5f3c8f
+    2a
+    ""
+    ""
+    622e5637;
+  ebfa921451dcd1af5813b70d30ce2f1fef6ef315d0
+    798391
+    ""
+    80
+    71
+    1a8cd2c7;
+  5da08da3aefc5f8584b7c5e617669c0f16e39815d4
+    e9cfce3ed1
+    ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6
+    bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147e
+    820f2b98a0887f75cabdd9085299ba9d20e0c02e0e997019
+    4b2b92958f792723;
+  d12ca986981a874498ad0abef8bc4fcb70e27e98ef
+    1f0446b42f
+    b144d44b6d00f06dc188d472a784e0c6f21195
+    a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016
+    04baa89b0f016a9eb9f9f555b539e33fde914515ab13f2506927f4a0db
+    266553d3216d3444;
+}
+
+des3-eax {
+  60d7bcda163547d348b7551195e7
+    ""
+    ""
+    ""
+    ""
+    fb8989aca27d4e49;
+  7022907dd1dff7dac5c9941d26d0
+    c6
+    ""
+    ""
+    ""
+    d6928baa49d00fad;
+  eb14ad568f86edd1dc9268eeee53
+    ""
+    32
+    ""
+    ""
+    33a565f808e5486a;
+  85a6ed810c9b689daaa9060d2d4b
+    ""
+    ""
+    60
+    79
+    a70d6c7cd5e64642;
+  03062365b0a54364c76c160f1189
+    6c4794846ecfa14a
+    7130c9f137120634c9519848a877ff77bf79192a5b50ade5
+    d9cd739a3d1f337f29549e6b0d27a4ba234085406a613651
+    9df7de45b395c138ed3f1c47399d41e00bad9d29625f6cbb
+    ffe26f440f8c69d8;
+  2061f7080cc07df0591d8fa21f2d
+    d88374d8cde8e1
+    60ad10997a21635c6d62c9269029df3e6057ac
+    c87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435
+    698d38628b4297877182f76af79b7a17fafba3580f403a1c0645416006
+    056a29aa5eec7e3b;
+  dceaa7b1cc49ae1d
+    ""
+    ""
+    ""
+    ""
+    cca6200e06749307;
+  50c38201a894476b
+    3f
+    ""
+    ""
+    ""
+    71f50318e1a16b5d;
+  102b752eb9529533
+    ""
+    96
+    ""
+    ""
+    b553cae3d6e4ccb5;
+  6f27043eb621b7f6
+    ""
+    ""
+    5b
+    eb
+    6f6d185a5644e5dc;
+  000961040ef2f9b2
+    fc5fa450727a9b54
+    2cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c9
+    5a97a48030370c33d090c54215abd6b3ad54efc9a38378c5
+    02f9df6832af2567bb074a96ff52ff9ef27cb6df55ed6912
+    6919ed7c6d0c9686;
+  b93bf4f2aad2605f
+    aee2b03fb648e2
+    7fff63102758fe2b69ac26afa3349829b94586
+    306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474
+    332681d1ab4ad4e8eee4f4b578efee58c917514f4d3c8ca33f50281a53
+    863ec2f3f702fa3a;
+  fd71d891f24bb65d1563259f9eb53b57
+    ""
+    ""
+    ""
+    ""
+    80199187ffd10cea;
+  1ea629c54d57dd2d42f70800df9fcbac
+    a4
+    ""
+    ""
+    ""
+    54afba7a1543f424;
+  8b77dba189196d1ebba10b0467cb9fc2
+    ""
+    71
+    ""
+    ""
+    9cb93469265f4d14;
+  2a199e533fa9156308cdec3f768281e0
+    ""
+    ""
+    40
+    80
+    e97aceb64f2af2bb;
+  a9b9a222bd689aef66f5306ceb0c6b08
+    ac8b0a22260c571b
+    4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8
+    368131115c037ba323fe1dc8151784873f0eb5b647da6794
+    e9d68e86a6b48c7d9c78122bda02edc1b1419cb3031c60e4
+    57fcc7556b89f2a9;
+  c18b5337685a96ed65b9aca338527ef1
+    9b09c063c46f88
+    de9fd41e72d7b97e23e6eabdff3bcd21149926
+    8878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100
+    f89817786143348d71bd1ee8d1016e7256a94589b86a3ce582d7a9a374
+    0add4b3bd1159ff5;
+  b8b649377d20a8f083455b663e4ee1315f3c8f2aeb
+    ""
+    ""
+    ""
+    ""
+    f7c8ae1e42180c1a;
+  fa921451dcd1af5813b70d30ce2f1fef6ef315d079
+    83
+    ""
+    ""
+    ""
+    b1dce877e070e318;
+  91805da08da3aefc5f8584b7c5e617669c0f16e398
+    ""
+    15
+    ""
+    ""
+    e373707f027e7557;
+  d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cd
+    ""
+    ""
+    f0
+    ef
+    b49b83dc48872748;
+  c8e30308be3c31e6bc58c0b7cadcb658b970e47479
+    a684b5aefa69a4cd
+    52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef
+    1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195
+    81e03369c6ecf1d8fb8c84a9817e0481b6de9ab9312737a4
+    f9ad8a3df2d97500;
+  a3b9f4ae985511265febd11c164720eef9eb1c8dd0
+    b00951f2846490
+    16ed00456331854bc78bf43966eb0cfa9138dd
+    c39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126
+    d05f8c73aa124cdfe56cd74db66498169f829858ed7ad4366d6388f6ae
+    1a54e1c0b2765dd8;
+}
+
+des3-gcm {
+  60d7bcda163547d348b7551195e7
+    ""
+    ""
+    ""
+    ""
+    132e46ca9dbab9db;
+  7022907dd1dff7dac5c9941d26d0
+    c6
+    ""
+    ""
+    ""
+    bfd51a7057175d5e;
+  eb14ad568f86edd1dc9268eeee53
+    ""
+    32
+    ""
+    ""
+    d86615981ba738da;
+  85a6ed810c9b689daaa9060d2d4b
+    ""
+    ""
+    60
+    58
+    ed191f4620eaf05c;
+  03062365b0a54364c76c160f1189
+    6c4794846ecfa14a
+    7130c9f137120634c9519848a877ff77bf79192a5b50ade5
+    d9cd739a3d1f337f29549e6b0d27a4ba234085406a613651
+    aa3017ec2824335d1d4ced7dfa26a12168b7f1666fc0c262
+    5f991803dc1e6270;
+  2061f7080cc07df0591d8fa21f2d
+    d88374d8
+    cde8e160ad10997a21635c
+    6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd
+    9c0ed71aaf781676ef39d8f8e1fc9688f0bb74b4b13346ef27c096114375191d99
+    1af29d5d8d54dd86;
+  4705e505da1435dceaa7b1cc49ae
+    1d50c38201a894
+    476b3f102b752eb9529533966f27043eb621b7
+    f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f
+    70bd822a653d5d478b5b833cba2e8317b4bc5cc0f3b63481cad478b43c
+    db44ad57ba2d5450;
+  215eb57bb3a4f3eb
+    ""
+    ""
+    ""
+    ""
+    1e48437f8a8d8ed9;
+  bbb18ac6c95a97a4
+    80
+    ""
+    ""
+    ""
+    a5cbaee18d95f020;
+  30370c33d090c542
+    ""
+    15
+    ""
+    ""
+    2d353887e03a32a7;
+  abd6b3ad54efc9a3
+    ""
+    ""
+    83
+    95
+    7e18fe4cf4d6debd;
+  78c5b93bf4f2aad2
+    605faee2b03fb648
+    e27fff63102758fe2b69ac26afa3349829b94586306fed54
+    154f8f28523c03d4de1600157846b710ee72807a2219bfb4
+    4db1999e265acd8766761cb5b48a3d7bf61e264daf209900
+    c498552a4665b7a1;
+  74fd71d891f24bb6
+    5d156325
+    9f9eb53b571ea629c54d57
+    dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533f
+    edcab4a157a12abde9e4743bd4d9351b0b6fe8c3b304c6daf3455197471e1eabdf
+    baf50f2e628a8632;
+  a9156308cdec3f76
+    8281e040a9b9a2
+    22bd689aef66f5306ceb0c6b08ac8b0a22260c
+    571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131
+    31865bdd67531355562674e18401ba3e453fc36b8390c5ef81802616fb
+    a837fdccf1d1647e;
+  115c037ba323fe1dc8151784873f0eb5
+    ""
+    ""
+    ""
+    ""
+    b81a0ef79153b70a;
+  b647da6794c18b5337685a96ed65b9ac
+    a3
+    ""
+    ""
+    ""
+    a519f2296fa3debe;
+  38527ef19b09c063c46f88de9fd41e72
+    ""
+    d7
+    ""
+    ""
+    5ec4b107491149c1;
+  b97e23e6eabdff3bcd211499268878db
+    ""
+    ""
+    f3
+    30
+    0824b10396c7f8ba;
+  0f1dad89d4b9b12012e4713df4679563
+    0e7952d22bb02d71
+    00b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa92
+    1451dcd1af5813b70d30ce2f1fef6ef315d0798391805da0
+    0237988024ea8379f5a851a1a1df21241c0f794ef45c528b
+    0bc36677cc8cad46;
+  8da3aefc5f8584b7c5e617669c0f16e3
+    9815d4e9
+    cfce3ed1ecdf3d264a7f16
+    cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5
+    0a501f6458635eb8074e565be165b71b922c8907caaa5bc385bb62a4f2711a70a5
+    d51e68d40adb01c0;
+  aefa69a4cd52147ed12ca986981a8744
+    98ad0abef8bc4f
+    cb70e27e98ef1f0446b42fb144d44b6d00f06d
+    c188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb
+    7af7a90baa5a4ec5904454bd0d62a3beafc988913073eb04f3748af96a
+    20721ecf26d54b13;
+  1c8dd0b00951f284649016ed00456331854bc78bf4
+    ""
+    ""
+    ""
+    ""
+    ac407ef838e78ff3;
+  3966eb0cfa9138ddc39908445608fe95e81c2533e3
+    1c
+    ""
+    ""
+    ""
+    de0e93debf2119fd;
+  9c1a9851bc2810d858cbbc8424d126b807e6daa089
+    ""
+    c3
+    ""
+    ""
+    292a3b10a3279110;
+  f9099c5ffb824173d7634c04226f30cbb7f0e4a973
+    ""
+    ""
+    a8
+    68
+    a0021d91c51fbdb5;
+  cd190107314717a77456f3ff669c732b58db8f48af
+    65f7cc9e3fb90e17
+    21b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a125
+    e47c416a265254284ec5ab752f010377d4ff57d4296ce09e
+    5e479801a05652fb;
+  8b2b9b8f0911e32d65cc1770a18cbfe6effd1ff677
+    8554acf1
+    270485b203a3c1c4c967c0
+    a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf4
+    2d0fcd3ec8e72558fb6cad34d3a93a7ad4b5b5940fdc77c1dfd733a1ddf5e093d5
+    2e35100e8d1e24fb;
+  3e89957f9a3e8128f8743d16687b7bb8deb9bd205b
+    70e04c091d205c
+    dad9e9a79b1abf91b0851e5ca605ac84513995
+    87011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397ab
+    fc2c1515c5fc3f727fb3e98ba249a076c3da8668f5e89db6e7956de064
+    a2411e499cacffef;
+}
+
+des3-ocb1 {
+  60d7bcda163547d348b7551195e7
+    7022907dd1dff7da
+    ""
+    ""
+    ""
+    cbd24ffb264f16ad;
+  c5c9941d26d0c6eb14ad568f86ed
+    d1dc9268eeee5332
+    85
+    ""
+    ""
+    a6e1ad4b16d8d99b;
+  a6ed810c9b689daaa9060d2d4b60
+    03062365b0a54364
+    ""
+    c7
+    a2
+    df1618790e682c74;
+  6c160f11896c4794846ecfa14a71
+    30c9f137120634c9
+    ""
+    519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29
+    51d9c953558e88ed892717edb5839471bab17ebda859fa2d
+    673b34362686d614;
+  549e6b0d27a4ba234085406a6136
+    512061f7080cc07d
+    f0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62
+    c9269029df3e6057acc87638f508046733d9ff61cdbda3b3
+    9e9db1333c288d89f1d852453679fd4a9df932ee424b56e6
+    0e15cfad6c6299f4;
+  e9878731ebfedd4705e505da1435
+    dceaa7b1cc49ae1d
+    ""
+    50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b0009
+    79f213b6e9d3b4a233652364a0741f0a3905112cdcc65fc6a1f02b20e1
+    fb385d47f056ea7a;
+  61040ef2f9b2fc5fa450727a9b54
+    2cde52ebfda19d0c
+    cc520f215eb57bb3a4f3ebbbb18ac6c95a97a4
+    8030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    1b7e1e5164841c4478deb10a87cc07f70db15af1b12790fb9f8ea16d79
+    e0d1715f5e9373c7;
+  aee2b03fb648e27f
+    ff63102758fe2b69
+    ""
+    ""
+    ""
+    4b884a39fbc7c745;
+  ac26afa3349829b9
+    4586306fed54154f
+    8f
+    ""
+    ""
+    d445ece0ef590e55;
+  28523c03d4de1600
+    157846b710ee7280
+    ""
+    7a
+    0e
+    020e28ecb1a51fd3;
+  2219bfb474fd71d8
+    91f24bb65d156325
+    ""
+    9f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77
+    a683ff420e8f9ea9467dd595afc344a0d25d20ea01c93b21
+    2748703cfe3e8226;
+  dba189196d1ebba1
+    0b0467cb9fc2712a
+    199e533fa9156308cdec3f768281e040a9b9a222bd689aef
+    66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa
+    aad5b6cbb6216005d17943984bb41bc4b6ba873ca43cb46b
+    d2c66cd04f05868e;
+  6a5cfb0bad7d9521
+    4ade49cb3b6f5fe8
+    ""
+    368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b533768
+    db8d34944ff3c0cdda5436416fb627c58f9b02d925b59a9b68fbbeda2a
+    06b84a7b2c9665a4;
+  5a96ed65b9aca338
+    527ef19b09c063c4
+    6f88de9fd41e72d7b97e23e6eabdff3bcd2114
+    99268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    db5cd9c16b245b3b5078d900f5d270cb81567d73703c2c95925a7237d3
+    eef56cad5b7f2ed2;
+  7100b8b649377d20a8f083455b663e4e
+    e1315f3c8f2aebfa
+    ""
+    ""
+    ""
+    56ad76ec7f013571;
+  921451dcd1af5813b70d30ce2f1fef6e
+    f315d0798391805d
+    a0
+    ""
+    ""
+    6542ea8693b8cd18;
+  8da3aefc5f8584b7c5e617669c0f16e3
+    9815d4e9cfce3ed1
+    ""
+    ec
+    35
+    90d173ba8349a22b;
+  df3d264a7f16cb16c2e815f422cdf0c8
+    e30308be3c31e6bc
+    ""
+    58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed1
+    64348fc5f46a28edab91b5d41e27ab352fa8ca90d322b603
+    b894f7a0cf918ae2;
+  2ca986981a874498ad0abef8bc4fcb70
+    e27e98ef1f0446b4
+    2fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae
+    985511265febd11c164720eef9eb1c8dd0b00951f2846490
+    dc70ae429c73fd871a49ab5aea8ed37196a151ad8d09dc3c
+    f76847ab0c01c5bd;
+  16ed00456331854bc78bf43966eb0cfa
+    9138ddc399084456
+    ""
+    08fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa0
+    7fcb46d49d63ecf4d49c4578841b1cc435362eb989098c8729fa7c8b7c
+    170621267d144a86;
+  89c3f9099c5ffb824173d7634c04226f
+    30cbb7f0e4a973a8
+    cd190107314717a77456f3ff669c732b58db8f
+    48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc
+    b0ecb19f5804122fb10b38ce2354dd1b9001c8e4f96d9f3a8b054ef79b
+    e3cfbcf2b101c897;
+  69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4f
+    fa91544485f1a125
+    ""
+    ""
+    ""
+    efc673f15d727525;
+  8b2b9b8f0911e32d65cc1770a18cbfe6effd1ff677
+    8554acf1270485b2
+    03
+    ""
+    ""
+    4be4ef9aa08e493e;
+  a3c1c4c967c0a458cb948bdd409b687fa3a6827b48
+    0aa3a4c84cef64f6
+    ""
+    c9
+    60
+    3c76403cf147a5a0;
+  b53bf8f957f4b03cf43e89957f9a3e8128f8743d16
+    687b7bb8deb9bd20
+    ""
+    5b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac84
+    6a5f5444d206a359b01efa29f51c6d3f13c050b663f1ea32
+    4ed8de43ccd151ef;
+  51399587011677508a15dde524af3e2bee0646541a
+    42c2ecccb44d65ba
+    d397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf
+    7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd2501
+    db5dbdd217bb8761aea78de2a51b9ab2bcb9559bfae22dfa
+    002834c8f3b3d2f1;
+  4107c8e7d715a92add9589d1f5c054b2d983514605
+    ec590294a319b980
+    ""
+    2068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59
+    9a6b4f24093acdff2a03f9a40494e1e6dd2ed10be75cdf9fb4381f7a1e
+    c492487046c80434;
+  a332ba58d5d5589bfe079753ee1a957eb6d6699e6b
+    7ea2725cb2dac07e
+    cde95759ac46fee6dda7abc8ad68daac90cfe2
+    2d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e6
+    14bc7ec21221fab0d0a55be9d505c315ef5ef5a01c9a5d8c71c6a8a569
+    598c7a7659a4ece7;
+}
+
+des3-pmac1 {
+  60d7bcda163547d348b7551195e7
+    ""
+    4ee97adb08a4f1ca;
+  7022907dd1dff7dac5c9941d26d0
+    c6
+    9280792119f1c90a;
+  eb14ad568f86edd1dc9268eeee53
+    3285a6ed810c9b689daaa9060d2d4b6003062365b0a54364
+    d3b9cda12ef855c9;
+  c76c160f11896c4794846ecfa14a
+    7130c9f137120634c9519848a877ff77bf7919
+    ccb225988c72647f;
+  2a5b50ade5d9cd73
+    ""
+    29b6cbd6a39de3ea;
+  9a3d1f337f29549e
+    6b
+    a44255ba14c7c82e;
+  0d27a4ba23408540
+    6a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8
+    4ae6eee38bf7dfc3;
+  e160ad10997a2163
+    5c6d62c9269029df3e6057acc87638f5080467
+    de786269abfb7dce;
+  33d9ff61cdbda3b3e9878731ebfedd47
+    ""
+    8e4e4d58688d0661;
+  05e505da1435dceaa7b1cc49ae1d50c3
+    82
+    1eb3af80bd877e09;
+  01a894476b3f102b752eb9529533966f
+    27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b54
+    ba1f17ab53c77f9c;
+  2cde52ebfda19d0ccc520f215eb57bb3
+    a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    614b8997f580de04;
+  4215abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    ""
+    79469a20ba34f900;
+  aee2b03fb648e27fff63102758fe2b69ac26afa334
+    98
+    69f377b3ea8e925c;
+  29b94586306fed54154f8f28523c03d4de16001578
+    46b710ee72807a2219bfb474fd71d891f24bb65d1563259f
+    6e0adaf190bd2ea1;
+  9eb53b571ea629c54d57dd2d42f70800df9fcbaca4
+    8b77dba189196d1ebba10b0467cb9fc2712a19
+    129deaeec0e03d30;
+}
+
+des3-ocb3 {
+  60d7bcda163547d348b7551195e7
+    7022907dd1df
+    ""
+    ""
+    ""
+    9bd7647cc6fc5088;
+  f7dac5c9941d26d0c6eb14ad568f
+    86edd1dc9268
+    ee
+    ""
+    ""
+    651a2beca10057bf;
+  ee533285a6ed810c9b689daaa906
+    0d2d4b600306
+    ""
+    23
+    61
+    55bdc89a749be10d;
+  65b0a54364c76c160f11896c4794
+    846ecf
+    ""
+    a14a7130c9f137120634c9519848a877ff77bf79192a5b50
+    04994fd2405c66040b24f1e112d12a373a5ded3204e93dfc
+    4d28060d06c1e6c9;
+  ade5d9cd739a3d1f337f29549e6b
+    0d27a4ba23
+    4085406a6136512061f7080cc07df0591d8fa21f2dd88374
+    d8cde8e160ad10997a21635c6d62c9269029df3e6057acc8
+    bd32ead43e0c7e3cdf30ec74e82e9db51a480c4bce6dfdfe
+    2440122fa77e088a;
+  7638f508046733d9ff61cdbda3b3
+    e9878731ebfe
+    ""
+    dd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752e
+    e7086ac5c54bba010b3597e95d8035ba213d20c55f50558f13f3725cb8
+    5f2cd9483cb3a2ac;
+  b9529533966f27043eb621b7f65b
+    000961040ef2
+    f9b2fc5fa450727a9b542cde52ebfda19d0ccc
+    520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215ab
+    960f222b5a4b66a7a416bf51be1cbfbaffd7626fd3449cfac5ec66cd94
+    0cfa7a7a8b52f6d3;
+  d6b3ad54efc9a383
+    78c5b93bf4f2
+    ""
+    ""
+    ""
+    f3be635a1f9bbcfa;
+  aad2605faee2b03f
+    b648e27fff63
+    10
+    ""
+    ""
+    27972bc75183a1f2;
+  2758fe2b69ac26af
+    a3349829b945
+    ""
+    86
+    6d
+    1449c4672751ce11;
+  306fed54154f8f28
+    523c03
+    ""
+    d4de1600157846b710ee72807a2219bfb474fd71d891f24b
+    2f9edc04b832738964e4ef2c18a17b1eaf8ec0a325e08b9d
+    df25c2d0f9430d6f;
+  b65d1563259f9eb5
+    3b571ea629
+    c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba1
+    0b0467cb9fc2712a199e533fa9156308cdec3f768281e040
+    c6b34746675339e4f07cc680e5b8e3e5da5541a92c659459
+    a6d7adc34d54cb89;
+  a9b9a222bd689aef
+    66f5306ceb0c
+    ""
+    6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49
+    79c706a66a8ebc8376e149588ab5584dcc7d59a37782abce2725bf2831
+    9d6ffb6e4cb098a5;
+  cb3b6f5fe8368131
+    115c037ba323
+    fe1dc8151784873f0eb5b647da6794c18b5337
+    685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6
+    da06bb4d2dc9612e2b9e1f38b4a9cf88c5f93c0ebbc12dc6894c42fb73
+    86be658d949b0120;
+  eabdff3bcd211499268878dbf30f1dad
+    89d4b9b12012
+    ""
+    ""
+    ""
+    a2599ce8b6a5832e;
+  e4713df46795630e7952d22bb02d7100
+    b8b649377d20
+    a8
+    ""
+    ""
+    1b9d7c64f893467a;
+  f083455b663e4ee1315f3c8f2aebfa92
+    1451dcd1af58
+    ""
+    13
+    d4
+    7702114c8465f527;
+  b70d30ce2f1fef6ef315d0798391805d
+    a08da3
+    ""
+    aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf
+    23275152a0a4c447adf86084cad8e537778f46150a4430aa
+    a44aba0c5685823a;
+  3d264a7f16cb16c2e815f422cdf0c8e3
+    0308be3c31
+    e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd5214
+    7ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f04
+    55917e61b80378e828b2cb53911b751df969fb0aaf39a0a1
+    cc006e8fa8f47da1;
+  46b42fb144d44b6d00f06dc188d472a7
+    84e0c6f21195
+    ""
+    a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016
+    67426920d7bb581d90c8c9b561d504d9729a024b2d26a34233f624bf35
+    3e0e6eaf9b8d41c2;
+  ed00456331854bc78bf43966eb0cfa91
+    38ddc3990844
+    5608fe95e81c2533e31c9c1a9851bc2810d858
+    cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cb
+    42eff82d31f0ca1cb79604219601c56c9d4e60ea08ab0e2be33b87fd70
+    70e2f64112ef6d62;
+  b7f0e4a973a8cd190107314717a77456f3ff669c73
+    2b58db8f48af
+    ""
+    ""
+    ""
+    f8608b8da49f9700;
+  65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2
+    f294b38766fc
+    69
+    ""
+    ""
+    df345d63832f4e3d;
+  f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa
+    91544485f1a1
+    ""
+    25
+    eb
+    17c6a45486274633;
+  8b2b9b8f0911e32d65cc1770a18cbfe6effd1ff677
+    8554ac
+    ""
+    f1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6
+    359c9f7d642db7d7d35ed57a183a25212c054d25a4de09e3
+    065d208592dbdc5c;
+  827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf4
+    3e89957f9a
+    3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cda
+    d9e9a79b1abf91b0851e5ca605ac8451399587011677508a
+    271c63ace6900ca3d2ea38737ff73f9298b4f6484ff4c916
+    32315b959ad39d8f;
+  15dde524af3e2bee0646541a42c2ecccb44d65bad3
+    97abfaf529ee
+    ""
+    41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdc
+    0a1bc356fb7cbe2959c09e1c504326d0544a16fa91596ca1bfbf69cd9f
+    0c1a33dffaebcbb8;
+  ccd213e33f7e8a5718fd25014107c8e7d715a92add
+    9589d1f5c054
+    b2d983514605ec590294a319b9802068a9f891
+    bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5
+    0e2f842eda3840dd0b22d2e5ec4e7280d96916ca08fa43b74ce34d1be9
+    32dc28ff4706c6fb;
+}
+
+des3-ocb3-mct {
+  24 d3d27b14989225a9;
+  21 eb3be38e3517c6d1;
+  16 07135a64481e5862;
+  14 812edbcd44bd9e1a;
+   8 d3d27b14989225a9;
+   7 eb3be38e3517c6d1;
+  24 70d5d3c75417;
+  21 93e83240fae6;
+  16 58382ba741ab;
+  14 6c492c0d482a;
+   8 70d5d3c75417;
+   7 93e83240fae6;
+  24 bdc8b8e1;
+  21 4407c007;
+  16 0654310f;
+  14 e2591768;
+   8 bdc8b8e1;
+   7 4407c007;
+}
index 0f64086..70bb222 100644 (file)
@@ -20,3 +20,909 @@ desx {
   00451338957377 4e6f772069732074 3fa40e8a984d4815;
   0123456789abcdef 4e6f772069732074 3fa40e8a984d4815;
 }
+
+desx-cmac {
+  60d7bcda163547d348b7551195e770
+    ""
+    a63cd9292fdf838b;
+  22907dd1dff7dac5c9941d26d0c6eb
+    14
+    a750bb7618266464;
+  ad568f86edd1dc9268eeee533285a6
+    ed810c9b689daaa9060d2d4b6003062365b0a54364c76c16
+    46adc2fa0e79b3b1;
+  0f11896c4794846ecfa14a7130c9f1
+    37120634c9519848a877ff77bf79192a5b50ad
+    68ba5dd6b52f40fb;
+  e5d9cd739a3d1f33
+    ""
+    3480b2e14686a332;
+  7f29549e6b0d27a4
+    ba
+    9bbb98b5d49df72c;
+  234085406a613651
+    2061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10
+    f2c52f3919204c2b;
+  997a21635c6d62c9
+    269029df3e6057acc87638f508046733d9ff61
+    e5acddb871d45625;
+  cdbda3b3e9878731ebfedd4705e505da
+    ""
+    08febcce60b0e724;
+  1435dceaa7b1cc49ae1d50c38201a894
+    47
+    80bdb1521243c0b1;
+  6b3f102b752eb9529533966f27043eb6
+    21b7f65b000961040ef2f9b2fc5fa450727a9b542cde52eb
+    86e00e79a5a63fc9;
+  fda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6
+    9b4ee9b29a9da89c;
+  b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648
+    ""
+    00413cee3fc9338f;
+  e27fff63102758fe2b69ac26afa3349829b94586306fed
+    54
+    f0bda4592cdc8ed1;
+  154f8f28523c03d4de1600157846b710ee72807a2219bf
+    b474fd71d891f24bb65d1563259f9eb53b571ea629c54d57
+    88158a6ce8f67fb2;
+  dd2d42f70800df9fcbaca48b77dba189196d1ebba10b04
+    67cb9fc2712a199e533fa9156308cdec3f7682
+    ebda61b856727ef6;
+}
+
+desx-ccm {
+  60d7bcda163547d348b7551195e770
+    22907d
+    ""
+    ""
+    ""
+    8ec46476;
+  d1dff7dac5c9941d26d0c6eb14ad56
+    8f86ed
+    d1
+    ""
+    ""
+    5f3af780;
+  dc9268eeee533285a6ed810c9b689d
+    aaa906
+    ""
+    0d
+    81
+    6bf70ba0;
+  2d4b6003062365b0a54364c76c160f
+    11896c4794
+    846ecfa14a7130c9f137120634c9519848a877ff77bf7919
+    2a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    0d411f5b72112442088bee58587f1b0acc6cdc2609b38528
+    263feadb0d5a70aa;
+  406a6136512061f7080cc07df0591d
+    8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    0b9ff20737a20741c3caa6bdad16930cce5fdbe1754d211e15701f547f
+    97f1a547f1179100;
+  05e505da1435dcea
+    a7b1cc
+    ""
+    ""
+    ""
+    001cf051;
+  49ae1d50c38201a8
+    94476b
+    3f
+    ""
+    ""
+    f4d9c98e;
+  102b752eb9529533
+    966f27
+    ""
+    04
+    a0
+    a8ed8162;
+  3eb621b7f65b0009
+    61040ef2f9
+    b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57b
+    b3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6
+    ab9b7c746d2bc3d9987a625049e1e17f09268f61914db075
+    af163edd14717f26;
+  b3ad54efc9a38378
+    c5b93bf4f2
+    aad2605faee2b03fb648e27fff63102758fe2b
+    69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846
+    222e460a7c0c877a3c3043bf46cd87c4b76b2dd7491d3d4dd22c8ea42f
+    c0d94d90dade32cb;
+  b710ee72807a2219bfb474fd71d891f2
+    4bb65d
+    ""
+    ""
+    ""
+    bd9bb6dc;
+  1563259f9eb53b571ea629c54d57dd2d
+    42f708
+    00
+    ""
+    ""
+    f24fb66d;
+  df9fcbaca48b77dba189196d1ebba10b
+    0467cb
+    ""
+    9f
+    cc
+    099a7f96;
+  c2712a199e533fa9156308cdec3f7682
+    81e040a9b9
+    a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42
+    bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe83681
+    15c1c73b28a6b905f4b301d941b961156ea6f145334295df
+    b81b11f44423b169;
+  31115c037ba323fe1dc8151784873f0e
+    b5b647da67
+    94c18b5337685a96ed65b9aca338527ef19b09
+    c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f
+    3999f0ebfb02f3e9163b462d325a844ada24367ab139617a32a4ac7f69
+    d7d9bc4926dce5fe;
+  1dad89d4b9b12012e4713df46795630e7952d22bb02d71
+    00b8b6
+    ""
+    ""
+    ""
+    e2278b44;
+  49377d20a8f083455b663e4ee1315f3c8f2aebfa921451
+    dcd1af
+    58
+    ""
+    ""
+    eb62b54e;
+  13b70d30ce2f1fef6ef315d0798391805da08da3aefc5f
+    8584b7
+    ""
+    c5
+    d7
+    72d0dd81;
+  e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb
+    16c2e815f4
+    22cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479
+    a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8
+    e709032bd184e5104714acdbd444b4ba1242692f504e8bbd
+    0e8982b121c86359;
+  bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188
+    d472a784e0
+    c6f21195a3b9f4ae985511265febd11c164720
+    eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa
+    157111d7f22ece6942850acb95f131f9749eb8625c0b6cef13fc859b62
+    690bf035ddf2b2db;
+}
+
+desx-eax {
+  60d7bcda163547d348b7551195e770
+    ""
+    ""
+    ""
+    ""
+    ee1840d22093ec87;
+  22907dd1dff7dac5c9941d26d0c6eb
+    14
+    ""
+    ""
+    ""
+    46bb7bcd888d7699;
+  ad568f86edd1dc9268eeee533285a6
+    ""
+    ed
+    ""
+    ""
+    64df2aefb68d65ae;
+  810c9b689daaa9060d2d4b60030623
+    ""
+    ""
+    65
+    bb
+    575efecd423272be;
+  b0a54364c76c160f11896c4794846e
+    cfa14a7130c9f137
+    120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    1f337f29549e6b0d27a4ba234085406a6136512061f7080c
+    2972fa4117846aea7de02f73eb27981c4b72524b1d8bfb72
+    abd123bd49b7e2e9;
+  c07df0591d8fa21f2dd88374d8cde8
+    e160ad10997a21
+    635c6d62c9269029df3e6057acc87638f50804
+    6733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49
+    35a431ef317b963514e1de6dfb568191eaa1bc89028e5868bcd25a8a3c
+    2693b4f76100e1df;
+  ae1d50c38201a894
+    ""
+    ""
+    ""
+    ""
+    c9fb343d394b7356;
+  476b3f102b752eb9
+    52
+    ""
+    ""
+    ""
+    47b15722772ba414;
+  9533966f27043eb6
+    ""
+    21
+    ""
+    ""
+    0d4b68956fb6f426;
+  b7f65b000961040e
+    ""
+    ""
+    f2
+    dd
+    8371e2b42301e2b0;
+  f9b2fc5fa450727a
+    9b542cde52ebfda1
+    9d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a4803037
+    0c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2
+    c199728a8cd014558621fcda5a5ce7765ba3770b43832210
+    84815299c2507a60;
+  605faee2b03fb648
+    e27fff63102758
+    fe2b69ac26afa3349829b94586306fed54154f
+    8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24b
+    bd352eea02065aa6352132121df385b3135e6598f1bbb589ed2c6044f1
+    6993814a37fada84;
+  b65d1563259f9eb53b571ea629c54d57
+    ""
+    ""
+    ""
+    ""
+    0a53de56ab1af32b;
+  dd2d42f70800df9fcbaca48b77dba189
+    19
+    ""
+    ""
+    ""
+    2539d47126f0cf9f;
+  6d1ebba10b0467cb9fc2712a199e533f
+    ""
+    a9
+    ""
+    ""
+    395bc02e7eefec9a;
+  156308cdec3f768281e040a9b9a222bd
+    ""
+    ""
+    68
+    ba
+    eb13f2c72c06d835;
+  9aef66f5306ceb0c6b08ac8b0a22260c
+    571b4a42bb8fdb23
+    3bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c03
+    7ba323fe1dc8151784873f0eb5b647da6794c18b5337685a
+    be11a99ec28d932e8064d57a7d3b6530cb137b8c05c397f2
+    9e116a03c63831e0;
+  96ed65b9aca338527ef19b09c063c46f
+    88de9fd41e72d7
+    b97e23e6eabdff3bcd211499268878dbf30f1d
+    ad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20
+    87f8e65dcf6034314eba4a952e6a6d0fc7595318f0cde2ba027276421e
+    0c029e501b79f342;
+  a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af58
+    ""
+    ""
+    ""
+    ""
+    f784fa0ed911d8ec;
+  13b70d30ce2f1fef6ef315d0798391805da08da3aefc5f
+    85
+    ""
+    ""
+    ""
+    14998b9f57e85a91;
+  84b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a
+    ""
+    7f
+    ""
+    ""
+    eaad2aaf758ba8cb;
+  16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7ca
+    ""
+    ""
+    dc
+    c6
+    05378e1a70ab191a;
+  b658b970e47479a684b5aefa69a4cd52147ed12ca98698
+    1a874498ad0abef8
+    bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d4
+    72a784e0c6f21195a3b9f4ae985511265febd11c164720ee
+    c5f5009fdbade4e487e8440429fc86aa782937bcdec0ca08
+    6feaef25c63b0802;
+  f9eb1c8dd0b00951f284649016ed00456331854bc78bf4
+    3966eb0cfa9138
+    ddc39908445608fe95e81c2533e31c9c1a9851
+    bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c
+    bf860edf5f2e423766bd979b97a8b90082ad8f015e2c24997603fe75e7
+    783c8dbade8c11f5;
+}
+
+desx-gcm {
+  60d7bcda163547d348b7551195e770
+    ""
+    ""
+    ""
+    ""
+    3cbc7b1df84dfef7;
+  22907dd1dff7dac5c9941d26d0c6eb
+    14
+    ""
+    ""
+    ""
+    37276edd9916fab0;
+  ad568f86edd1dc9268eeee533285a6
+    ""
+    ed
+    ""
+    ""
+    88e93bc3d86c7bf8;
+  810c9b689daaa9060d2d4b60030623
+    ""
+    ""
+    65
+    4b
+    742b8f2a4982002f;
+  b0a54364c76c160f11896c4794846e
+    cfa14a7130c9f137
+    120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    1f337f29549e6b0d27a4ba234085406a6136512061f7080c
+    ae84aba1c0a431bfee3521370654d195518e43fbbcae082e
+    8ae1456ca69792a7;
+  c07df0591d8fa21f2dd88374d8cde8
+    e160ad10
+    997a21635c6d62c9269029
+    df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da14
+    4f97aead4260eff9a4c1e39ef827ce568f08fcb95f2245503953f5c1e5b02036fb
+    b685fc67d7bac453;
+  35dceaa7b1cc49ae1d50c38201a894
+    476b3f102b752e
+    b9529533966f27043eb621b7f65b000961040e
+    f2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3
+    e8df8e4af153dbf70d1517d2f6d388f02705dd53c25b7f5c9d7c6c60f8
+    fa07533070e3b62b;
+  ebbbb18ac6c95a97
+    ""
+    ""
+    ""
+    ""
+    52880f24cb1c97c4;
+  a48030370c33d090
+    c5
+    ""
+    ""
+    ""
+    ea8c5fd1be78bb6b;
+  4215abd6b3ad54ef
+    ""
+    c9
+    ""
+    ""
+    6130a7a2a73d2517;
+  a38378c5b93bf4f2
+    ""
+    ""
+    aa
+    bf
+    6a2baada10b09a4f;
+  d2605faee2b03fb6
+    48e27fff63102758
+    fe2b69ac26afa3349829b94586306fed54154f8f28523c03
+    d4de1600157846b710ee72807a2219bfb474fd71d891f24b
+    353616debc97a081ea320a9a6379498465389fc12a30c97e
+    29ae2d4f192ff073;
+  b65d1563259f9eb5
+    3b571ea6
+    29c54d57dd2d42f70800df
+    9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f
+    e098b62b321e856c615d30d670b21afbbecc1c01d58184165b0d766819f149ff4d
+    afd78ddc422cde3b;
+  768281e040a9b9a2
+    22bd689aef66f5
+    306ceb0c6b08ac8b0a22260c571b4a42bb8fdb
+    233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe
+    44c55447399ff836d71fa8adc5975f7fe504a62f8a031d118e9bdb8592
+    3aec6e5c527595ee;
+  1dc8151784873f0eb5b647da6794c18b
+    ""
+    ""
+    ""
+    ""
+    b649714dae520d42;
+  5337685a96ed65b9aca338527ef19b09
+    c0
+    ""
+    ""
+    ""
+    0f7b54a0f0e759de;
+  63c46f88de9fd41e72d7b97e23e6eabd
+    ""
+    ff
+    ""
+    ""
+    b5332afef45bc1e2;
+  3bcd211499268878dbf30f1dad89d4b9
+    ""
+    ""
+    b1
+    d9
+    7d02b1fcfd1d0d3e;
+  2012e4713df46795630e7952d22bb02d
+    7100b8b649377d20
+    a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813
+    b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584
+    902dda67a4bf1b44cc8f2b788541da0946d53815390326c4
+    b2a841f844b8b948;
+  b7c5e617669c0f16e39815d4e9cfce3e
+    d1ecdf3d
+    264a7f16cb16c2e815f422
+    cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd5214
+    cfb2568095e376c9f50aed2f781748b98a68629a13f81842b6ed3315fe03633a37
+    9188774ecda5437a;
+  7ed12ca986981a874498ad0abef8bc4f
+    cb70e27e98ef1f
+    0446b42fb144d44b6d00f06dc188d472a784e0
+    c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f2
+    be0fd7ae8afa1502f49e7616bd5a20956f3ce40c05b3ec395eefc2ee91
+    d16dddd5c97d9dad;
+  84649016ed00456331854bc78bf43966eb0cfa9138ddc3
+    ""
+    ""
+    ""
+    ""
+    35514c76e6059f2d;
+  9908445608fe95e81c2533e31c9c1a9851bc2810d858cb
+    bc
+    ""
+    ""
+    ""
+    88e733af8182afbd;
+  8424d126b807e6daa089c3f9099c5ffb824173d7634c04
+    ""
+    22
+    ""
+    ""
+    fa4d035dde2e7d7c;
+  6f30cbb7f0e4a973a8cd190107314717a77456f3ff669c
+    ""
+    ""
+    73
+    45
+    706978229672282f;
+  2b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597
+    f56ccbb2f294b387
+    66fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa
+    91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6ef
+    9b5a4d527d5bc4c52350bb496dcbda3b072b99173b55d90d
+    9b96c04ec2f5504e;
+  fd1ff6778554acf1270485b203a3c1c4c967c0a458cb94
+    8bdd409b
+    687fa3a6827b480aa3a4c8
+    4cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd
+    63b58db88053af9da1f93879beea44bee6faa6a2c672aefc6ec5517b273cecda73
+    edbc4b6c82c99d4d;
+  205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605
+    ac845139958701
+    1677508a15dde524af3e2bee0646541a42c2ec
+    ccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf
+    e6bc35974509d938a953ad32ae829a5cced3f2846e756fbc99247ae1d5
+    623e465c7913e6b2;
+}
+
+desx-ocb1 {
+  60d7bcda163547d348b7551195e770
+    22907dd1dff7dac5
+    ""
+    ""
+    ""
+    caa9db9c2fd96b20;
+  c9941d26d0c6eb14ad568f86edd1dc
+    9268eeee533285a6
+    ed
+    ""
+    ""
+    e3f19e04d004771a;
+  810c9b689daaa9060d2d4b60030623
+    65b0a54364c76c16
+    ""
+    0f
+    ce
+    274fa8d10ec38416;
+  11896c4794846ecfa14a7130c9f137
+    120634c9519848a8
+    ""
+    77ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d
+    286bf711ca2f9d9e6e3ea11390d46225834d56c3cadef9f3
+    8a3e9e27a8bd1267;
+  27a4ba234085406a6136512061f708
+    0cc07df0591d8fa2
+    1f2dd88374d8cde8e160ad10997a21635c6d62c9269029df
+    3e6057acc87638f508046733d9ff61cdbda3b3e9878731eb
+    e9a1c82381cb138e2b635f58ec9ad77e81eee97cb9b725cf
+    2c08bbda5c67ae28;
+  fedd4705e505da1435dceaa7b1cc49
+    ae1d50c38201a894
+    ""
+    476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2
+    77c71af12f7e75599be17868608c1e66a767d5324a43d136777c8298f2
+    da3b49f25c22648f;
+  fc5fa450727a9b542cde52ebfda19d
+    0ccc520f215eb57b
+    b3a4f3ebbbb18ac6c95a97a48030370c33d090
+    c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e2
+    e93425b446b6e0ee7622d56eb8781430e61c0b79fbf75b5129e66be0df
+    aaae9e5df22ffd66;
+  7fff63102758fe2b
+    69ac26afa3349829
+    ""
+    ""
+    ""
+    2454c6d4af0543c6;
+  b94586306fed5415
+    4f8f28523c03d4de
+    16
+    ""
+    ""
+    57f09f05b22aed2a;
+  00157846b710ee72
+    807a2219bfb474fd
+    ""
+    71
+    07
+    98a03e06427d6c6e;
+  d891f24bb65d1563
+    259f9eb53b571ea6
+    ""
+    29c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebb
+    79bc018164ccf90123ed426c5e261171c67c69512e8f41b1
+    d83eb8863b890872;
+  a10b0467cb9fc271
+    2a199e533fa91563
+    08cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b
+    08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95
+    2b050493ae97a338a539cf0a46f443a137a90bce681c3cf7
+    cca806fe40ecdf0d;
+  214ade49cb3b6f5f
+    e8368131115c037b
+    ""
+    a323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca3
+    49d25f8e34f3dfac53f8409552f42c89167889d2cbe2af5ba0ba4c2dfc
+    7051575c9d170e37;
+  38527ef19b09c063
+    c46f88de9fd41e72
+    d7b97e23e6eabdff3bcd211499268878dbf30f
+    1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d
+    bfe9acab806680bdc205fdaf72e274eeec6698801454fc94a8c0c16262
+    4f53c9ecfbb5f758;
+  20a8f083455b663e4ee1315f3c8f2aeb
+    fa921451dcd1af58
+    ""
+    ""
+    ""
+    0230f537d84fad83;
+  13b70d30ce2f1fef6ef315d079839180
+    5da08da3aefc5f85
+    84
+    ""
+    ""
+    03faa4ac602dc7ed;
+  b7c5e617669c0f16e39815d4e9cfce3e
+    d1ecdf3d264a7f16
+    ""
+    cb
+    18
+    a514a198a9c98049;
+  16c2e815f422cdf0c8e30308be3c31e6
+    bc58c0b7cadcb658
+    ""
+    b970e47479a684b5aefa69a4cd52147ed12ca986981a8744
+    7fb1ffb913b75f8d4c7ea6e84a9f2fc911380d1b8ee343f6
+    2a496d014b16a40a;
+  98ad0abef8bc4fcb70e27e98ef1f0446
+    b42fb144d44b6d00
+    f06dc188d472a784e0c6f21195a3b9f4ae985511265febd1
+    1c164720eef9eb1c8dd0b00951f284649016ed0045633185
+    722aa22fa02f13d32187730cb051fa3b49fcd9a308a9d453
+    c59459ba824bc1a5;
+  4bc78bf43966eb0cfa9138ddc3990844
+    5608fe95e81c2533
+    ""
+    e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb
+    86c1f74d4db77a90398574f168f83e6de15e6a2b7b2afa621590dc0404
+    4543ce1f721609f4;
+  824173d7634c04226f30cbb7f0e4a973
+    a8cd190107314717
+    a77456f3ff669c732b58db8f48af65f7cc9e3f
+    b90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945f
+    cfa9cfeddbc593bd6812352a35fa31e2a53b1840ea430ee8e2085d60da
+    90bfab3707b05a6a;
+  fd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b
+    2b9b8f0911e32d65
+    ""
+    ""
+    ""
+    7a861a7d3af428f9;
+  cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1
+    c4c967c0a458cb94
+    8b
+    ""
+    ""
+    ff1c4c7bc330ef39;
+  dd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f9
+    57f4b03cf43e8995
+    ""
+    7f
+    d2
+    b1cb7d2102d5c32c;
+  9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d20
+    5cdad9e9a79b1abf
+    ""
+    91b0851e5ca605ac8451399587011677508a15dde524af3e
+    9bdb27bbfc7389090471f3cb7051cb8d1fd530005e21a93f
+    3bd9da825a402482;
+  2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf
+    9a05c7efedef3401
+    539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f
+    7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d9
+    b569d836ce07d26017bdecdc06938abe11f29988e2ee4eaa
+    7c12ae284dab4140;
+  83514605ec590294a319b9802068a9f891bc5ba5afabf8
+    c3122d12d7ff3c41
+    ""
+    122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d669
+    c893ff49cfec7dfa04b6c966ff8e2de2dbca702ed6cd0416b4d1e12b2a
+    4f6e8bdaed610893;
+  9e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad
+    68daac90cfe22d2f
+    1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6
+    254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b000
+    e5977138d0d737d7b616047aa523dc1b7d5b5fb6fd20e26831a2f34bb8
+    6e42e08c54165845;
+}
+
+desx-pmac1 {
+  60d7bcda163547d348b7551195e770
+    ""
+    4af29214a7b8f451;
+  22907dd1dff7dac5c9941d26d0c6eb
+    14
+    497e34853501b17c;
+  ad568f86edd1dc9268eeee533285a6
+    ed810c9b689daaa9060d2d4b6003062365b0a54364c76c16
+    be4cb7dd9428ff3f;
+  0f11896c4794846ecfa14a7130c9f1
+    37120634c9519848a877ff77bf79192a5b50ad
+    bd394b556e88691a;
+  e5d9cd739a3d1f33
+    ""
+    cf37166cf40c5a63;
+  7f29549e6b0d27a4
+    ba
+    36f50dc5278f6d48;
+  234085406a613651
+    2061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10
+    afa0c00f1d78a165;
+  997a21635c6d62c9
+    269029df3e6057acc87638f508046733d9ff61
+    0cb5b03ffdf32b7e;
+  cdbda3b3e9878731ebfedd4705e505da
+    ""
+    12307602abf4cd83;
+  1435dceaa7b1cc49ae1d50c38201a894
+    47
+    7b6c2a63bc1599df;
+  6b3f102b752eb9529533966f27043eb6
+    21b7f65b000961040ef2f9b2fc5fa450727a9b542cde52eb
+    ec16536d65cbf867;
+  fda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6
+    b0548570d2b43e37;
+  b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648
+    ""
+    1e5b6857738e4db7;
+  e27fff63102758fe2b69ac26afa3349829b94586306fed
+    54
+    3739adab4d52a786;
+  154f8f28523c03d4de1600157846b710ee72807a2219bf
+    b474fd71d891f24bb65d1563259f9eb53b571ea629c54d57
+    54f3e5fc1458f0a3;
+  dd2d42f70800df9fcbaca48b77dba189196d1ebba10b04
+    67cb9fc2712a199e533fa9156308cdec3f7682
+    462473f2102f3c1d;
+}
+
+desx-ocb3 {
+  60d7bcda163547d348b7551195e770
+    22907dd1dff7
+    ""
+    ""
+    ""
+    421aa0e31e3c1a41;
+  dac5c9941d26d0c6eb14ad568f86ed
+    d1dc9268eeee
+    53
+    ""
+    ""
+    7bb6a8ce983ccb5e;
+  3285a6ed810c9b689daaa9060d2d4b
+    6003062365b0
+    ""
+    a5
+    0d
+    ca4e70eaefa59040;
+  4364c76c160f11896c4794846ecfa1
+    4a7130
+    ""
+    c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd
+    d0075d682bb032d318f435f35ed9e7e0dd2e759b18346051
+    3c5c9c5dab448848;
+  739a3d1f337f29549e6b0d27a4ba23
+    4085406a61
+    36512061f7080cc07df0591d8fa21f2dd88374d8cde8e160
+    ad10997a21635c6d62c9269029df3e6057acc87638f50804
+    2b0daddf1c1562ed4ec92feba5fc19abb1a7d7fe85035cc3
+    b574000108612b30;
+  6733d9ff61cdbda3b3e9878731ebfe
+    dd4705e505da
+    ""
+    1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f
+    f9d6ea23faa8a36974e06d38d9061790875f1e4523e9f8eccb89dd8c13
+    73bdbd55cfa011e8;
+  27043eb621b7f65b000961040ef2f9
+    b2fc5fa45072
+    7a9b542cde52ebfda19d0ccc520f215eb57bb3
+    a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a3
+    21b80b17c3caf1e5b5fdabe9f9ce4fec36e20cae0a9c9b1e85167041be
+    68f794a0eb64f247;
+  8378c5b93bf4f2aa
+    d2605faee2b0
+    ""
+    ""
+    ""
+    fd8891d8d9802520;
+  3fb648e27fff6310
+    2758fe2b69ac
+    26
+    ""
+    ""
+    ce479a676926cc17;
+  afa3349829b94586
+    306fed54154f
+    ""
+    8f
+    d7
+    d92beba1b5d650db;
+  28523c03d4de1600
+    157846
+    ""
+    b710ee72807a2219bfb474fd71d891f24bb65d1563259f9e
+    6818636db15d3a46dc05078583752a6a774b1b514bdea903
+    c5958bbdef31bba2;
+  b53b571ea629c54d
+    57dd2d42f7
+    0800df9fcbaca48b77dba189196d1ebba10b0467cb9fc271
+    2a199e533fa9156308cdec3f768281e040a9b9a222bd689a
+    22dfcb714017ac0ad765d20593b65444a234a59dd3fc1abb
+    aa605331fbc55268;
+  ef66f5306ceb0c6b
+    08ac8b0a2226
+    ""
+    0c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe83681
+    40a58a44dd58cd9e44d06391edc4ec2916d3b29628c61ad9084f56cc29
+    436c5a2b1728295f;
+  31115c037ba323fe
+    1dc815178487
+    3f0eb5b647da6794c18b5337685a96ed65b9ac
+    a338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd2114
+    2b6d4c2462ad510a000d9df521066c02a81e31d5873c66343deb78fce2
+    77a855f0a7d42e18;
+  99268878dbf30f1dad89d4b9b12012e4
+    713df4679563
+    ""
+    ""
+    ""
+    2685c7810bf996c5;
+  0e7952d22bb02d7100b8b649377d20a8
+    f083455b663e
+    4e
+    ""
+    ""
+    a25ea075d7bc735a;
+  e1315f3c8f2aebfa921451dcd1af5813
+    b70d30ce2f1f
+    ""
+    ef
+    ef
+    e4ea88484e9e6b1e;
+  6ef315d0798391805da08da3aefc5f85
+    84b7c5
+    ""
+    e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16
+    fd6a65b03ae4567f3c6a94e573da790cb684b8d5bd32e3fd
+    754c91fb0050e81e;
+  c2e815f422cdf0c8e30308be3c31e6bc
+    58c0b7cadc
+    b658b970e47479a684b5aefa69a4cd52147ed12ca986981a
+    874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b
+    5c9347f1dc4853413edfe418d369932c21212122dac2955d
+    92362b5fed50868c;
+  6d00f06dc188d472a784e0c6f21195a3
+    b9f4ae985511
+    ""
+    265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854b
+    6f62164db8d9a857e36ca6eef9bbdcba9d01743165ee7acd87fe754d0d
+    a55e71bcc128168d;
+  c78bf43966eb0cfa9138ddc399084456
+    08fe95e81c25
+    33e31c9c1a9851bc2810d858cbbc8424d126b8
+    07e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd
+    1c394e0b510d366554dd0afcb0c6b0b4e9437fb1c83355753863e2eec9
+    86560f52894b7d41;
+  190107314717a77456f3ff669c732b58db8f48af65f7cc
+    9e3fb90e1721
+    ""
+    ""
+    ""
+    a4205f9ab2399111;
+  b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    945ffd505003
+    cc
+    ""
+    ""
+    5078f8d6fa0e866a;
+  0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911
+    e32d65cc1770
+    ""
+    a1
+    32
+    87fddf9b28a92f55;
+  8cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0
+    a458cb
+    ""
+    948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8
+    b1af8fefb936518c083e54b9c67363455a1f642e253c0918
+    159d0ce2b235b273;
+  f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8de
+    b9bd205b70
+    e04c091d205cdad9e9a79b1abf91b0851e5ca605ac845139
+    9587011677508a15dde524af3e2bee0646541a42c2ecccb4
+    ef425d80e98f3681592695628ed0a816418fa5899b1d1d42
+    f29bb2c9e21839c7;
+  4d65bad397abfaf529ee41cf9a05c7efedef3401539c51
+    d2a90bbf7f1b
+    ""
+    fc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a9
+    2c4a2be80fd7d3f7b3b5a4ef05a6540fb6798601ad3623aaab10d0ac60
+    a1ed9a02743fa18a;
+  2add9589d1f5c054b2d983514605ec590294a319b98020
+    68a9f891bc5b
+    a5afabf8c3122d12d7ff3c41122d70d17d4569
+    eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2
+    81c230d8f7e0294cbbb8fe659f94a74332801000f5b5f49b74ce635cc0
+    9d5ceb6d322cfa12;
+}
+
+desx-ocb3-mct {
+  24 b8a0fa1c0e3e1201;
+  23 b8a0fa1c0e3e1201;
+  16 08afcdeda8acc974;
+  15 0c967b6cca833a3c;
+   8 d3d27b14989225a9;
+   7 eb3be38e3517c6d1;
+  24 0418ab9332b6;
+  23 0418ab9332b6;
+  16 aff581b9de59;
+  15 2b546df8e00c;
+   8 70d5d3c75417;
+   7 93e83240fae6;
+  24 802690b2;
+  23 802690b2;
+  16 cf467380;
+  15 c874e69c;
+   8 bdc8b8e1;
+   7 4407c007;
+}
diff --git a/symm/t/gcm b/symm/t/gcm
new file mode 100644 (file)
index 0000000..cf2b162
--- /dev/null
@@ -0,0 +1,976 @@
+### Low-level tests for GCM multiplication.
+
+gcm-mul64 {
+  cde4bef260d7bcda
+    163547d348b75511
+    c9ee47ed2b156ee9;
+  95e77022907dd1df
+    f7dac5c9941d26d0
+    6dbd5c9c416492a6;
+  c6eb14ad568f86ed
+    d1dc9268eeee5332
+    08bdf4e9bf8c1f93;
+  85a6ed810c9b689d
+    aaa9060d2d4b6003
+    0cf6ee6642648823;
+  062365b0a54364c7
+    6c160f11896c4794
+    79f08ae100e469b0;
+  846ecfa14a7130c9
+    f137120634c95198
+    9f105828be4871c9;
+  48a877ff77bf7919
+    2a5b50ade5d9cd73
+    474a0e6c8b786a42;
+  9a3d1f337f29549e
+    6b0d27a4ba234085
+    44071433860810ec;
+  406a6136512061f7
+    080cc07df0591d8f
+    a09f47fee5c90487;
+  a21f2dd88374d8cd
+    e8e160ad10997a21
+    d1a3ae2849f6e1b3;
+  635c6d62c9269029
+    df3e6057acc87638
+    4d02197152061f71;
+  f508046733d9ff61
+    cdbda3b3e9878731
+    3b567fc5b2fad254;
+  ebfedd4705e505da
+    1435dceaa7b1cc49
+    dee51993e134cdcf;
+  ae1d50c38201a894
+    476b3f102b752eb9
+    8e3e6132a84c2062;
+  529533966f27043e
+    b621b7f65b000961
+    262098e88d669837;
+  040ef2f9b2fc5fa4
+    50727a9b542cde52
+    ad129933b7f306e5;
+  ebfda19d0ccc520f
+    215eb57bb3a4f3eb
+    95e06cd4d7f6453a;
+  bbb18ac6c95a97a4
+    8030370c33d090c5
+    0acd90305b863292;
+  4215abd6b3ad54ef
+    c9a38378c5b93bf4
+    9f21b3656650b80d;
+  f2aad2605faee2b0
+    3fb648e27fff6310
+    53448ad6016b5a88;
+  2758fe2b69ac26af
+    a3349829b9458630
+    7a114f9030a64751;
+  6fed54154f8f2852
+    3c03d4de16001578
+    91532dc3dcd1b8fe;
+  46b710ee72807a22
+    19bfb474fd71d891
+    877c3092f14be92e;
+  f24bb65d1563259f
+    9eb53b571ea629c5
+    26fa6c3a6205f520;
+  4d57dd2d42f70800
+    df9fcbaca48b77db
+    baa61b8ee2efee4b;
+  a189196d1ebba10b
+    0467cb9fc2712a19
+    a7b5b29b8359b2d3;
+  9e533fa9156308cd
+    ec3f768281e040a9
+    30ae2526b8601e66;
+  b9a222bd689aef66
+    f5306ceb0c6b08ac
+    3656b2206364b85f;
+  8b0a22260c571b4a
+    42bb8fdb233bfa6a
+    351d3f9025791fb4;
+  5cfb0bad7d95214a
+    de49cb3b6f5fe836
+    3c571fdf110d88d3;
+  8131115c037ba323
+    fe1dc8151784873f
+    a5280a7d7bf3fbd5;
+  0eb5b647da6794c1
+    8b5337685a96ed65
+    15a80ceb4c5612d9;
+  b9aca338527ef19b
+    09c063c46f88de9f
+    506d2129368b3535;
+  d41e72d7b97e23e6
+    eabdff3bcd211499
+    a9485bc115054e16;
+  268878dbf30f1dad
+    89d4b9b12012e471
+    d33c8040301aa9d6;
+  3df46795630e7952
+    d22bb02d7100b8b6
+    c351d03535b15a43;
+  49377d20a8f08345
+    5b663e4ee1315f3c
+    659490124597d0ac;
+  8f2aebfa921451dc
+    d1af5813b70d30ce
+    a1265ff538452f9b;
+  2f1fef6ef315d079
+    8391805da08da3ae
+    090119c5295ce005;
+  fc5f8584b7c5e617
+    669c0f16e39815d4
+    fc0d6997230f9340;
+  e9cfce3ed1ecdf3d
+    264a7f16cb16c2e8
+    173b0d65b7f7defa;
+  15f422cdf0c8e303
+    08be3c31e6bc58c0
+    95789ad1072e5991;
+  b7cadcb658b970e4
+    7479a684b5aefa69
+    5681dbf13399af21;
+  a4cd52147ed12ca9
+    86981a874498ad0a
+    69266124234d8824;
+  bef8bc4fcb70e27e
+    98ef1f0446b42fb1
+    9ce3c0c2bd679e5d;
+  44d44b6d00f06dc1
+    88d472a784e0c6f2
+    d4d0dde377de138c;
+  1195a3b9f4ae9855
+    11265febd11c1647
+    324150243bf34600;
+  20eef9eb1c8dd0b0
+    0951f284649016ed
+    15cb17aa733f44ba;
+  00456331854bc78b
+    f43966eb0cfa9138
+    4c8fd598a01bf479;
+  ddc39908445608fe
+    95e81c2533e31c9c
+    5341133994016920;
+  1a9851bc2810d858
+    cbbc8424d126b807
+    470ff40df79063ab;
+  e6daa089c3f9099c
+    5ffb824173d7634c
+    0a778cecd0cafb7a;
+  04226f30cbb7f0e4
+    a973a8cd19010731
+    85a0294ea292354a;
+  4717a77456f3ff66
+    9c732b58db8f48af
+    636a37a3d5c97941;
+  65f7cc9e3fb90e17
+    21b730374ffc9bc5
+    64dccdd7dfb08b84;
+  97f56ccbb2f294b3
+    8766fc69f6a9f2c0
+    bf6f50d14cf7e5b8;
+  945ffd505003cc0c
+    ae9ce021a5f1fa4f
+    37035c953d053e5f;
+  fa91544485f1a125
+    8b2b9b8f0911e32d
+    9c50f40823733f0b;
+  65cc1770a18cbfe6
+    effd1ff6778554ac
+    11d7d33017171bc2;
+  f1270485b203a3c1
+    c4c967c0a458cb94
+    75e2e1a04e3ad3d7;
+  8bdd409b687fa3a6
+    827b480aa3a4c84c
+    e40958395d2015c9;
+  ef64f6c9b53bf8f9
+    57f4b03cf43e8995
+    cc0ff0246e3ea756;
+  7f9a3e8128f8743d
+    16687b7bb8deb9bd
+    e7afa3631ceb1d83;
+  205b70e04c091d20
+    5cdad9e9a79b1abf
+    295070cfdc2c3748;
+}
+
+gcm-mul96 {
+  cde4bef260d7bcda163547d3
+    48b7551195e77022907dd1df
+    4eec45fb8fc3b3e39aac7aae;
+  f7dac5c9941d26d0c6eb14ad
+    568f86edd1dc9268eeee5332
+    05134f056f51918c72e23289;
+  85a6ed810c9b689daaa9060d
+    2d4b6003062365b0a54364c7
+    bcfba16699cf54c7b4827b8c;
+  6c160f11896c4794846ecfa1
+    4a7130c9f137120634c95198
+    b831f2da94b112266bd6bc3e;
+  48a877ff77bf79192a5b50ad
+    e5d9cd739a3d1f337f29549e
+    5ad06fd826c670ca741020ec;
+  6b0d27a4ba234085406a6136
+    512061f7080cc07df0591d8f
+    e29fc44efee1497b3d29ef65;
+  a21f2dd88374d8cde8e160ad
+    10997a21635c6d62c9269029
+    5cc40a00243b31c565f37eba;
+  df3e6057acc87638f5080467
+    33d9ff61cdbda3b3e9878731
+    dccd19797b205b612986e298;
+  ebfedd4705e505da1435dcea
+    a7b1cc49ae1d50c38201a894
+    e8be723b884eb9f69e388db1;
+  476b3f102b752eb952953396
+    6f27043eb621b7f65b000961
+    bc04044aaaef558b55e3dd7b;
+  040ef2f9b2fc5fa450727a9b
+    542cde52ebfda19d0ccc520f
+    de533f5f43678c1072d64ef8;
+  215eb57bb3a4f3ebbbb18ac6
+    c95a97a48030370c33d090c5
+    861b3f005e294a74ae9d78b5;
+  4215abd6b3ad54efc9a38378
+    c5b93bf4f2aad2605faee2b0
+    bd3d716b1535654fc1336c3f;
+  3fb648e27fff63102758fe2b
+    69ac26afa3349829b9458630
+    9199c9fc5fe891d9b22fe7c5;
+  6fed54154f8f28523c03d4de
+    1600157846b710ee72807a22
+    66f5090ef7912cd1c4b4ebec;
+  19bfb474fd71d891f24bb65d
+    1563259f9eb53b571ea629c5
+    11a1ad6bd0e17aa45aa29d18;
+  4d57dd2d42f70800df9fcbac
+    a48b77dba189196d1ebba10b
+    5887206626c27472a811261c;
+  0467cb9fc2712a199e533fa9
+    156308cdec3f768281e040a9
+    f6c50c86da0692784633b96a;
+  b9a222bd689aef66f5306ceb
+    0c6b08ac8b0a22260c571b4a
+    6b5169d0ead2cf118bead4a1;
+  42bb8fdb233bfa6a5cfb0bad
+    7d95214ade49cb3b6f5fe836
+    23aeda3be39212e86bc0be3b;
+  8131115c037ba323fe1dc815
+    1784873f0eb5b647da6794c1
+    711e6d0a1d2f28008b8c1ff1;
+  8b5337685a96ed65b9aca338
+    527ef19b09c063c46f88de9f
+    5fcf403f2c1cbd40c5a2b2bf;
+  d41e72d7b97e23e6eabdff3b
+    cd211499268878dbf30f1dad
+    8f025a46e6a1c48a74cad7a4;
+  89d4b9b12012e4713df46795
+    630e7952d22bb02d7100b8b6
+    e147d342d3feee155226d69b;
+  49377d20a8f083455b663e4e
+    e1315f3c8f2aebfa921451dc
+    bd0327387c43f688f66cdbbe;
+  d1af5813b70d30ce2f1fef6e
+    f315d0798391805da08da3ae
+    08fa0a0c901d0d0965968170;
+  fc5f8584b7c5e617669c0f16
+    e39815d4e9cfce3ed1ecdf3d
+    98add0390bd310fa096f453f;
+  264a7f16cb16c2e815f422cd
+    f0c8e30308be3c31e6bc58c0
+    cd186496b610dd8764aa152d;
+  b7cadcb658b970e47479a684
+    b5aefa69a4cd52147ed12ca9
+    c2de0b36d4dea7af5bbaf035;
+  86981a874498ad0abef8bc4f
+    cb70e27e98ef1f0446b42fb1
+    9d2ab48640b402ade690ca33;
+  44d44b6d00f06dc188d472a7
+    84e0c6f21195a3b9f4ae9855
+    6c5c40b6a299efd5663d5010;
+  11265febd11c164720eef9eb
+    1c8dd0b00951f284649016ed
+    3c0b6a72988abb596a30e347;
+  00456331854bc78bf43966eb
+    0cfa9138ddc39908445608fe
+    7e180f9395090b8646d62aa4;
+  95e81c2533e31c9c1a9851bc
+    2810d858cbbc8424d126b807
+    78ae33d19f5d9ba3b2158f0a;
+  e6daa089c3f9099c5ffb8241
+    73d7634c04226f30cbb7f0e4
+    922a3fa3bb9704aa3cb0c627;
+  a973a8cd190107314717a774
+    56f3ff669c732b58db8f48af
+    f5996b9d374f4174367ca998;
+  65f7cc9e3fb90e1721b73037
+    4ffc9bc597f56ccbb2f294b3
+    799bda7e13675b504cc15d48;
+  8766fc69f6a9f2c0945ffd50
+    5003cc0cae9ce021a5f1fa4f
+    62aaf766cc72b312acf6b867;
+  fa91544485f1a1258b2b9b8f
+    0911e32d65cc1770a18cbfe6
+    5fe1f589f40181cef0aeaf9b;
+  effd1ff6778554acf1270485
+    b203a3c1c4c967c0a458cb94
+    8847d0b844fc9063ff111626;
+  8bdd409b687fa3a6827b480a
+    a3a4c84cef64f6c9b53bf8f9
+    1b937802f75d4ebc4f3d7a86;
+  57f4b03cf43e89957f9a3e81
+    28f8743d16687b7bb8deb9bd
+    a53eb13d45700a7885120b81;
+  205b70e04c091d205cdad9e9
+    a79b1abf91b0851e5ca605ac
+    d448d6ac6e6eb01171b14634;
+  8451399587011677508a15dd
+    e524af3e2bee0646541a42c2
+    dab29efd14f77990ca5d724a;
+  ecccb44d65bad397abfaf529
+    ee41cf9a05c7efedef340153
+    fea1ab4c3083794c01303a23;
+  9c51d2a90bbf7f1bfc338ab0
+    ef5746ea8fdcccd213e33f7e
+    74b7906ccadf56726f06016c;
+  8a5718fd25014107c8e7d715
+    a92add9589d1f5c054b2d983
+    20656261ca5136c2bf69b1d1;
+  514605ec590294a319b98020
+    68a9f891bc5ba5afabf8c312
+    55d0d749027044ab80ecfb46;
+  2d12d7ff3c41122d70d17d45
+    69eaff59a332ba58d5d5589b
+    a4de245c51057e4ca49e06d7;
+  fe079753ee1a957eb6d6699e
+    6b7ea2725cb2dac07ecde957
+    ad498f1966703fd2cbad5b6d;
+  59ac46fee6dda7abc8ad68da
+    ac90cfe22d2f1f2968cc42fa
+    f415976427d6fe6ff4547d08;
+  8b669ed3bb3542a9cf44bbc8
+    c6254d980398bd94e66eb456
+    afe3c9c5ded2010edc99564f;
+  3d405e51881e99027b8ab9ae
+    a3ccf860b0009740763d9683
+    1ee6d3bc94ea166843327955;
+  6c5f87b95460938de1288c69
+    d80ea12ff4bb5f069b8a2e86
+    046ba565c8674b84f22ac9a3;
+  041c1b9fc214e9ca2186ddf1
+    f6a7a3aa7e740da967828e36
+    9c0b170f7e8ca9958dcfc12f;
+  04b35b15ffaa6c36800d9645
+    563a308ba60076817523bd2a
+    cff407868fb153b9b51fface;
+  bf1261b089d8f23a9c283507
+    6a23faac2cdd67771cc667a8
+    7006da38a1cf3992ef37b338;
+  331f0a170b66283e4f834a06
+    148f302c3973accd56f6f24e
+    d493d3e118362ffe57ffce5a;
+  33958b8c2e2352fd61e4fa8f
+    ec816ac861a8b33779f09e7a
+    f700eeecf80cfd35a7c249c8;
+  10fc02a8f48afa3080ee119a
+    52a9a817e4f2b94b0820cab3
+    41f9bc5aceef5e3c164829d6;
+  83a8cffeea7c486315799dc8
+    75fba578c8ec4837898a9214
+    9ab99439ea7108fdd2b3a68a;
+  2b5b0677da1ac273117b45bc
+    fff5d5f8b6fde2893232a9f8
+    ed9e4c863cac39665c322566;
+  1d14517ffae475f6b94a43a6
+    7b3d380d2f9aaafe2dd721c0
+    a84bebd2a47410cb5320cd55;
+  095c8808847689211450ba80
+    95ffab1eaadf66fd22ac1976
+    09742e21f274088ba0c8fcc0;
+}
+
+gcm-mul128 {
+  cde4bef260d7bcda163547d348b75511
+    95e77022907dd1dff7dac5c9941d26d0
+    ae22821f55ada6b996c3818891f4ec1d;
+  c6eb14ad568f86edd1dc9268eeee5332
+    85a6ed810c9b689daaa9060d2d4b6003
+    c23e2072f3dbef54a6d43f840a45cd25;
+  062365b0a54364c76c160f11896c4794
+    846ecfa14a7130c9f137120634c95198
+    e4c3bf75dfae8f6201d306bb612d2757;
+  48a877ff77bf79192a5b50ade5d9cd73
+    9a3d1f337f29549e6b0d27a4ba234085
+    b5e1c1885725019124e64e12a7f7a284;
+  406a6136512061f7080cc07df0591d8f
+    a21f2dd88374d8cde8e160ad10997a21
+    83dc338673e6dce375f0c9e9c3853a3f;
+  635c6d62c9269029df3e6057acc87638
+    f508046733d9ff61cdbda3b3e9878731
+    48660987fa15f010812e499b7e448508;
+  ebfedd4705e505da1435dceaa7b1cc49
+    ae1d50c38201a894476b3f102b752eb9
+    1be7a7b553d5f4e88c6bdda1162fc56b;
+  529533966f27043eb621b7f65b000961
+    040ef2f9b2fc5fa450727a9b542cde52
+    7c48e4ab5e27e4f79f7c02e4e171cc2b;
+  ebfda19d0ccc520f215eb57bb3a4f3eb
+    bbb18ac6c95a97a48030370c33d090c5
+    45d12390797c08a0c3cc9244cd56b922;
+  4215abd6b3ad54efc9a38378c5b93bf4
+    f2aad2605faee2b03fb648e27fff6310
+    c53ccfdb25d06cd49acea8481c953bb7;
+  2758fe2b69ac26afa3349829b9458630
+    6fed54154f8f28523c03d4de16001578
+    413a6503df527330e38a5e62d61677da;
+  46b710ee72807a2219bfb474fd71d891
+    f24bb65d1563259f9eb53b571ea629c5
+    4c22f463e2528bfff499d3337d32a921;
+  4d57dd2d42f70800df9fcbaca48b77db
+    a189196d1ebba10b0467cb9fc2712a19
+    068a3e3a1cf5552b90d915e565c76c47;
+  9e533fa9156308cdec3f768281e040a9
+    b9a222bd689aef66f5306ceb0c6b08ac
+    1463b22c7b22f4b483ceff293a405c18;
+  8b0a22260c571b4a42bb8fdb233bfa6a
+    5cfb0bad7d95214ade49cb3b6f5fe836
+    d1be35fea22f3168cb22d7b044c4a53b;
+  8131115c037ba323fe1dc8151784873f
+    0eb5b647da6794c18b5337685a96ed65
+    39ee791290bd770cc3747c82e906de45;
+  b9aca338527ef19b09c063c46f88de9f
+    d41e72d7b97e23e6eabdff3bcd211499
+    5e39550b65471a1a5a8db0a1a36ba3a6;
+  268878dbf30f1dad89d4b9b12012e471
+    3df46795630e7952d22bb02d7100b8b6
+    f1f7219c57aca09072abd1a4b5dc211c;
+  49377d20a8f083455b663e4ee1315f3c
+    8f2aebfa921451dcd1af5813b70d30ce
+    c53ec2fa18d6dd8749295e7246056537;
+  2f1fef6ef315d0798391805da08da3ae
+    fc5f8584b7c5e617669c0f16e39815d4
+    ba9f8b1bbaaca05549621835352a0732;
+  e9cfce3ed1ecdf3d264a7f16cb16c2e8
+    15f422cdf0c8e30308be3c31e6bc58c0
+    e24b90e7ca7ee0094901641a6ed9efe3;
+  b7cadcb658b970e47479a684b5aefa69
+    a4cd52147ed12ca986981a874498ad0a
+    6a8831e02852976a844c69f551cd6617;
+  bef8bc4fcb70e27e98ef1f0446b42fb1
+    44d44b6d00f06dc188d472a784e0c6f2
+    d8ede7cda85607c85ca2aa454275cab5;
+  1195a3b9f4ae985511265febd11c1647
+    20eef9eb1c8dd0b00951f284649016ed
+    b7690610ba96abfaa395dc709830c17d;
+  00456331854bc78bf43966eb0cfa9138
+    ddc39908445608fe95e81c2533e31c9c
+    7b23455563491e6234d7f3976ed92534;
+  1a9851bc2810d858cbbc8424d126b807
+    e6daa089c3f9099c5ffb824173d7634c
+    4111b410f25d6c27ef36e4c0744e06dd;
+  04226f30cbb7f0e4a973a8cd19010731
+    4717a77456f3ff669c732b58db8f48af
+    f3ed8ac5133b62dc453bb3b845371f07;
+  65f7cc9e3fb90e1721b730374ffc9bc5
+    97f56ccbb2f294b38766fc69f6a9f2c0
+    97bd7eac33021557df0c54ca9b45c4b3;
+  945ffd505003cc0cae9ce021a5f1fa4f
+    fa91544485f1a1258b2b9b8f0911e32d
+    074736b8f03cfe2d058b60a60c1c42b2;
+  65cc1770a18cbfe6effd1ff6778554ac
+    f1270485b203a3c1c4c967c0a458cb94
+    e6159e8e83f7acbcd6e3c1530ec97a31;
+  8bdd409b687fa3a6827b480aa3a4c84c
+    ef64f6c9b53bf8f957f4b03cf43e8995
+    47c1e7905f2f87b6a522a2eb83b6e7cd;
+  7f9a3e8128f8743d16687b7bb8deb9bd
+    205b70e04c091d205cdad9e9a79b1abf
+    48d09e17f51f54cb44113d4f22d19bee;
+  91b0851e5ca605ac8451399587011677
+    508a15dde524af3e2bee0646541a42c2
+    7b880e45b35f9b942de7b817ad2d3921;
+  ecccb44d65bad397abfaf529ee41cf9a
+    05c7efedef3401539c51d2a90bbf7f1b
+    0f092a20ab3a445fa314921920e68a7b;
+  fc338ab0ef5746ea8fdcccd213e33f7e
+    8a5718fd25014107c8e7d715a92add95
+    b03bdb56bcea03d7a98444d06c4d9949;
+  89d1f5c054b2d983514605ec590294a3
+    19b9802068a9f891bc5ba5afabf8c312
+    7c950c3817abf217b1bb67c78dbc9ce1;
+  2d12d7ff3c41122d70d17d4569eaff59
+    a332ba58d5d5589bfe079753ee1a957e
+    22164f3d69c20fb9a211645810a980b5;
+  b6d6699e6b7ea2725cb2dac07ecde957
+    59ac46fee6dda7abc8ad68daac90cfe2
+    f916129ec57c478ffd99077e76fb9f0b;
+  2d2f1f2968cc42fa8b669ed3bb3542a9
+    cf44bbc8c6254d980398bd94e66eb456
+    ccacc0839b857afecba7bbd5ca6b2e2c;
+  3d405e51881e99027b8ab9aea3ccf860
+    b0009740763d96836c5f87b95460938d
+    b5dc31fc7ae8d1a7c4b638fa22490910;
+  e1288c69d80ea12ff4bb5f069b8a2e86
+    041c1b9fc214e9ca2186ddf1f6a7a3aa
+    9445b9b898beeb32a4d1ce0ab979c740;
+  7e740da967828e3604b35b15ffaa6c36
+    800d9645563a308ba60076817523bd2a
+    765a9b5e6dd62f8b3bba62382a58f149;
+  bf1261b089d8f23a9c2835076a23faac
+    2cdd67771cc667a8331f0a170b66283e
+    7ae006a4c122e24d4f7e3ff2c6f1354d;
+  4f834a06148f302c3973accd56f6f24e
+    33958b8c2e2352fd61e4fa8fec816ac8
+    2935d8d91408993ddb7a7d0d8db8516a;
+  61a8b33779f09e7a10fc02a8f48afa30
+    80ee119a52a9a817e4f2b94b0820cab3
+    ae4fd2f3a8d384e0b395461a8e326022;
+  83a8cffeea7c486315799dc875fba578
+    c8ec4837898a92142b5b0677da1ac273
+    9b0c75856b1c2972cb990106690d373b;
+  117b45bcfff5d5f8b6fde2893232a9f8
+    1d14517ffae475f6b94a43a67b3d380d
+    5b7b6a4fdfcf0c8a6d67f240458b70f3;
+  2f9aaafe2dd721c0095c880884768921
+    1450ba8095ffab1eaadf66fd22ac1976
+    729752ad6453d80b3d31e7433be19add;
+  063e113ab61f813e28a1397a7974a1d7
+    f4220c785fe426a5a0e80f678d404147
+    dc51774484281b3ab9cd2859a1f91063;
+  842941feeffdc2eb44dc8c0d5e8f444f
+    7f4e0c893959b74dc23a7bb40e7e0013
+    1a01406d34cf1da32e48b55e792b37e9;
+  e5150686d2301b43a15a84e81d7f5ced
+    aa49e2414ebf47970e560475cff20687
+    0e9125c21526a8dc35085476ffbd523d;
+  7de69146acc3ab6cf8556b7aa7769459
+    48d1b8834df2196c92ec1718dcdeee0d
+    31df775698abd477c7c389bbade1026b;
+  52d9539726d2810391b3f9d10c39b07a
+    e8f08ce7cee4758a386a9943e97dedfb
+    87800aad52281a95fb85fb4679774add;
+  e61e737882cd09c2b9a80f34c0fde11c
+    2481b11fc76bfa4dbf710a9e544e0c53
+    a3b71ba7cd2e15c70cd5d40d6d145d1b;
+  6ca1e040f9ad5b04140d98edabe08485
+    290a4d87d13b07398a1458c2c6b61dbd
+    fdba17a43c6d190d2318855a2645748b;
+  bc1cccada8c1a0a9aabb6c4e3c3554f8
+    fb1ef61614c270295dfc0ca6551ca4bd
+    c7eabdcdea64775c683fa87614816b9e;
+  b75359f91cb9d921056b7de74fc9a9b3
+    7154ce6c0b396179d31f06a1dd5982cb
+    a3fa226d9cd4183023e8061d3c3c7666;
+  c0d7cb23841da1ae8f4ae480cda98ad6
+    cf2bacf6f9fd3f821330c43f3df6c2b3
+    635a20300e343fbd26211c9ff3ea26d5;
+  fac7cbcf96523d4723f91801325eb855
+    3236651c96788d73d192ee53b3f3ebd6
+    1ac40bd24b41dcc095e25dd6f5647d68;
+  6ddd98cedbe88e245de25b1593b70f86
+    01562d90a9b59ed034a867642d25d547
+    fe9b405f0a0e3d917075a2ce8282a881;
+  56fa5c47f16f64b837bb4926214211a1
+    c696ba172010abb433922a22d9fd8815
+    384b8bc7a4a1135a6bdf3c36756b0774;
+  19165eb9d85197a21cc34ac0d5ae7be8
+    dbf98e4ffed2cf6b1372a5aa47b54fd9
+    0b197a28af39b496a4d82db88cfa51b2;
+  d70c70e117bf1cae71b3a56f0e7d839e
+    a59cc783443d64f2ed6a29b96856beca
+    ab4ef17dac09d42ecaaac8d50643d89a;
+  34fd6544bcf86b799e2a1681160ccf05
+    5f0fd3001da597a1406d465b7b1419ea
+    c964db11b22df7e476eac1448500114e;
+}
+
+gcm-mul192 {
+  cde4bef260d7bcda163547d348b7551195e77022907dd1df
+    f7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee5332
+    3bf1ea9b1ebee7e9444aaf08e585b09b31e67d3c95c9612d;
+  85a6ed810c9b689daaa9060d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9f137120634c95198
+    aa859fbc2a8ddcff234ac6e350b0e0c1a62f882f77219ce3;
+  48a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e
+    6b0d27a4ba234085406a6136512061f7080cc07df0591d8f
+    6caddb90ad1aaf422acc28e99d650fa1a3d7b480101b3b32;
+  a21f2dd88374d8cde8e160ad10997a21635c6d62c9269029
+    df3e6057acc87638f508046733d9ff61cdbda3b3e9878731
+    f8d6b247d97ac3252c49a7544bbde8a0e45a999bc81b156b;
+  ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894
+    476b3f102b752eb9529533966f27043eb621b7f65b000961
+    27177d063a813ad4be51f4360cb3933bf6ccc1bb64c5cb32;
+  040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f
+    215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    c03117b28345bbbbdf657e220e2f23de46743a5591e66d69;
+  4215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b0
+    3fb648e27fff63102758fe2b69ac26afa3349829b9458630
+    9c0ce16e01e9376fb28c571aa2401c7be69cabc249323ab4;
+  6fed54154f8f28523c03d4de1600157846b710ee72807a22
+    19bfb474fd71d891f24bb65d1563259f9eb53b571ea629c5
+    e869d24bde7293357bb17686c423591a891c40eb75e9cf8c;
+  4d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b
+    0467cb9fc2712a199e533fa9156308cdec3f768281e040a9
+    26ca24fde1d3d37a5e3dc72acf6d2b31ab1d084caa3dc205;
+  b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a
+    42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836
+    ee889525ce4e6531e0eb218a0e72bdad13ecc5a1842d16f6;
+  8131115c037ba323fe1dc8151784873f0eb5b647da6794c1
+    8b5337685a96ed65b9aca338527ef19b09c063c46f88de9f
+    12eeda395ce56e2170f6671f527f165f1992cc1940b552f7;
+  d41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad
+    89d4b9b12012e4713df46795630e7952d22bb02d7100b8b6
+    55153969c52056416bfd39a39cd2417339c800620227b450;
+  49377d20a8f083455b663e4ee1315f3c8f2aebfa921451dc
+    d1af5813b70d30ce2f1fef6ef315d0798391805da08da3ae
+    7e3e26d9c6514465ae7258f1ed4909c83ea1bbcb8a0b2947;
+  fc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d
+    264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0
+    8acad6c66a7d17fc4e55a164408cf9ad42974ee147d6fd0f;
+  b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca9
+    86981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb1
+    b62791c6430580b6921bda4e8f0dc67a3cd4c344ba87a56a;
+  44d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae9855
+    11265febd11c164720eef9eb1c8dd0b00951f284649016ed
+    9a063e0f09a4fc2e41a63b38564fc07c578df43375a31c9b;
+  00456331854bc78bf43966eb0cfa9138ddc39908445608fe
+    95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807
+    6eb9bc75eb709c4a6f63d8121d25b8777f5ea3af865ce812;
+  e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4
+    a973a8cd190107314717a77456f3ff669c732b58db8f48af
+    0b3e51503a58f410adb27a6203a8966d47657d481a302d23;
+  65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b3
+    8766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4f
+    82de8284669677b6832d83675af4fe5462636a530459d49a;
+  fa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6
+    effd1ff6778554acf1270485b203a3c1c4c967c0a458cb94
+    61d8b471ee449edb41627d254bfbfcbca10babbc1460d5f8;
+  8bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f9
+    57f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd
+    254a831b866aad0f5e51943fc70c5ccaa7b9adba85762f00;
+  205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac
+    8451399587011677508a15dde524af3e2bee0646541a42c2
+    418f551166e166e2e89fdc3d3a7a1e60e50e472c349da9de;
+  ecccb44d65bad397abfaf529ee41cf9a05c7efedef340153
+    9c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e
+    ecf94369195385ea66741348bd0e796c461293ad8b1d1895;
+  8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983
+    514605ec590294a319b9802068a9f891bc5ba5afabf8c312
+    245f715f907f93b9b5277b55f844f5b4aa732ac698a76f95;
+  2d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589b
+    fe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde957
+    233a36249df31b12a3da455a1ff4c34f457399aa9ae8194c;
+  59ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa
+    8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb456
+    db7a3e16e9aafeab616ce0fd985073f9eefbcb08c69985b7;
+  3d405e51881e99027b8ab9aea3ccf860b0009740763d9683
+    6c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86
+    7fc4a6d0b794e1bc893a00969479168876f166d1140aa9e7;
+  041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e36
+    04b35b15ffaa6c36800d9645563a308ba60076817523bd2a
+    da67471cfae7c99a25eb0f23d5081e6f05888ef4c7c5651a;
+  bf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8
+    331f0a170b66283e4f834a06148f302c3973accd56f6f24e
+    6a391d4b0a662c09d3807c90dfcb8f230e260dacb89943e0;
+  33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a
+    10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab3
+    8ae8f405accb95e13d86bed19e63f6d6efe47264a46960ca;
+  83a8cffeea7c486315799dc875fba578c8ec4837898a9214
+    2b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f8
+    72892f188dce0da69ee68b3782ead0d40f1748fbec7dfd06;
+  1d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0
+    095c8808847689211450ba8095ffab1eaadf66fd22ac1976
+    281ef0eff8afd5233318b564c8ed228e76c075ba61e7bd6b;
+  063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5
+    a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f
+    4fa4ca4d35e133d9d94815fc1bd294792bf73d2cb470eef3;
+  7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43
+    a15a84e81d7f5cedaa49e2414ebf47970e560475cff20687
+    9d7c763547460f559d2ace4bc185f365e0c634e9ddffe0fd;
+  7de69146acc3ab6cf8556b7aa776945948d1b8834df2196c
+    92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07a
+    33c5a1a6645c8ea5e2a1bd5c3d8a05ed1fbf25bc16b969b1;
+  e8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2
+    b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c53
+    14ed2a6864c16b031fe425f0edd51930c4e09a1672e28578;
+  6ca1e040f9ad5b04140d98edabe08485290a4d87d13b0739
+    8a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8
+    ae886c5aa093d9c66b6de64062eccf3c5d2c3fb763bdde09;
+  fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921
+    056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cb
+    877d80fe26e43415303f4590f934354f265aefc3aa7bf85c;
+  c0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f82
+    1330c43f3df6c2b3fac7cbcf96523d4723f91801325eb855
+    9ffdb8a099964dd83b1936e57a1c3511c92c68e0c712d1ba;
+  3236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e24
+    5de25b1593b70f8601562d90a9b59ed034a867642d25d547
+    6bd995f6829d0ac4d313f7ab100ea03ffbac19de700dce3a;
+  56fa5c47f16f64b837bb4926214211a1c696ba172010abb4
+    33922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8
+    1fbdf165adb07f53ff3ea39a33a82ab9a5cb243259c5ec1d;
+  dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae
+    71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca
+    14c2eb66e8aa8bdcd09978ebcb905473a8edff6c771da7f1;
+  34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1
+    406d465b7b1419ea51cf858f938f6daafbd656445a09898e
+    c1f403fe552c5a3d008512eb2d015705e149072ce1d3e69a;
+  aa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eed
+    b969ffe07669845ebb7a24c69f13d099f47166edf54538e8
+    a033fe30ee8714a173e1fd5c821ff2c5aeaeda27c3a9dcca;
+  8fbf433a7ff212085179e79771f6eee7283ab178ef2b800d
+    7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901
+    ecff14eb486025a840e4b7d8b43075a87de1cac31cf05804;
+  ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e90029
+    26ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb
+    936b458a28fc0c6de0ea6f10e49cc13892899a112fa175b4;
+  84241986c251f5b70be2367f047265264e0da72efe8995e6
+    c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279
+    c106ea40f0e1a1cab89dfd44d27bec7ad878e4bfdefb1c8a;
+  d54d03f0e0f3e961dcfd40088d5be74088e4097efb0368c7
+    e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d
+    5962497cc337df2622d05213a1d8a5048ad7f017cc53b01e;
+  907eab7707ca48ff5ba1ae93d16225d469de5747bc1addf5
+    748729720a320fe14fd29cfc59314fe2079c0a2535ded561
+    cec57ed2e38528db38facc00e2cc658f681f371ccd55af54;
+  12d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9ca
+    f02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd1
+    d4186ea94ce6b6e90797ce6c5c09a2f136e758b7bbc332a0;
+  8c374fc43581d2f72a89584a2404a059f7f99c7241a0c879
+    d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3
+    55dc606dc9bad711515603b589f1e1227c03826c0d017b3d;
+  bc6d94238ab56d738e02abd651477cd726d6f3ebcd6fadea
+    b50906642a7de6496247060e7be3632ed9bd94bb42f45a87
+    97ef18739ec98e9cff77ca3f323b567df45c8ca5e5f3b310;
+  33b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad
+    09a5b8fa687ec3bad8e18dc2ad361f1e226e78876cd35f86
+    5671fca885dd004ba927253cd0342c5e0bfbdaddc608dcd0;
+  c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b61
+    2ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c83983
+    e587e42c1e61c6ceadea37c68bfb715e01a15c47730ac81b;
+  9c1b06319f687dbc68d9f07fd41ccb4f8cde8de201ec2680
+    332bbded4883deea0b58b54bdd13c17ef292b0ded3caeb5e
+    87aa1604b5d3a8bc2b6b8bc67d37a3dbfc3d12b19cbc43ae;
+  57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea
+    358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dc
+    9e06e282ca2a9286bedf70783876f36cc238cca76cf81dab;
+  c73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7
+    496993a25b072945d83f923e66b0a6689cf0969c003a8fca
+    54ce4a46639bb8b1627fcb98bb76270c615f5a4411c8c754;
+  80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b
+    9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee7
+    0b77cb7790f367b2b8465ddec635b6d272e78c5f8670dab0;
+  8ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf
+    2fb5b205e592c172a5cbc19456c95c1bea6079f3867e52d6
+    3dbca1bf0639237a10ee151674812fb5a4459614d405ea17;
+  63cb3884b2a0a8ff825df752423f3179bfeb89eca385f20d
+    dce5f1f23564672e370ffc37d400a31e8aac1d426ce10df7
+    3186bd4e2bd9b82499779406fa93fe98d2d74a9de4f94cfe;
+  3c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286b6
+    27e7d01b38a84a6de738721ed80fd0d7f69fa658abb5a440
+    83f9caa8826f361ae7b7015fed42ed61d964258e4b9aa944;
+  d304128719b541a9451cead18e4c61d93d1f8fcc53574427
+    767396322b3bf7d02cec05093696cec07591ada462271b1d
+    a6cb63d9b94d2269e85bb551f019180b8daaf1461946a2f1;
+  1519eedde0df37a330fe8c22ebd77705917b7e32ae88f45a
+    34a8ba3037235e19a394be4d26ce47317d8087684456b4cf
+    25e012b33b54bb9734315020b02651a8476dd2af54fa9e39;
+  c5555e925e3e7b2ebc829b2d0505ea617b0ca9531bcdb960
+    40d39040e632d562643ccb64286303040fcaf679e914eadd
+    b059b9be9e7700024accda083f56f569ac51e624ed72a7ed;
+}
+
+gcm-mul256 {
+  cde4bef260d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0
+    c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003
+    789615a0602ce0d6e57a94074e22645fcdca1c2530cdce6a3a9898eefa48f602;
+  062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c95198
+    48a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    ccd7a63e0f43d900d461f137b5f9a1b797580961dfe96d9e85ce0cc154f608ee;
+  406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21
+    635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731
+    5f81e704e9b04d5b517392c372c5d2756eacc4f7a9442ac98d4bf8bb8536fe89;
+  ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9
+    529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52
+    094e95ea9c8346285f98c6f07ddd15830aa193170953a8abc41712732c76c336;
+  ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    4215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff6310
+    52d7772d1f860c1ce6cb4d1259577c2d43421ebfc44c89c43f05d0f424401b34;
+  2758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de16001578
+    46b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c5
+    ad51dbcde8d0216bc998500d67317c852d273252d39d2c6a555d22a4fd180959;
+  4d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a19
+    9e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac
+    f25c5e462dc2a069bedb1d39ee68b16d025c0596ca27efd01c46555b245f6087;
+  8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836
+    8131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    934d35daaec3791e39e799c81c62f07b1628bcd3113eecc4cc13993fad10e629;
+  b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499
+    268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b6
+    99845195dba2f3b005653321a028907e11f546e597a641d652d85dae95e1775e;
+  49377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce
+    2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4
+    16edc22df1c67d480ba3d471d61097eeba54e40ca0bf06d6fdd84232677efd19;
+  e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0
+    b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0a
+    49b59d9642e48bb2116b5b2515b77ba746e6ae804e8e9ed83ca2322a800a9ae6;
+  bef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f2
+    1195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed
+    6d03d43d9d7afc91f749c061d63dde21753f303c5d070e34dde5193c27e13046;
+  00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c
+    1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c
+    fd315ad2958b91405b2895b81391997c56a599609bdcd17ce9f2d540689374c1;
+  04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af
+    65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    4978b31536da1b90c44b6dfa1e874a37d4442a9e65979465998ae5ef0599fdfe;
+  945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d
+    65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb94
+    d64e275582ac14f23502aa43a0c2819e236e28770d72f3e9fe0d91b1cfe18d2d;
+  8bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e8995
+    7f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf
+    32223b066ce69f5963af0f7e121424ad3ab03d818562327eb0a495e7b0a0a844;
+  91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2
+    ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1b
+    98abd767205b0f7fe21909f48b6182430169836df1712981bc1ae96b4e5c1b2b;
+  fc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add95
+    89d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c312
+    35446e8c959e35b74ff4e8960a1c80c3a4fc60998fc074d3fa6d73e7787b2bdc;
+  2d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957e
+    b6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe2
+    b893278872133d6ae9370dd0c1bf7e6990438ef83b012db8b4ac0197ee115ac1;
+  2d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb456
+    3d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938d
+    b954c35b504dd99c3f95f2778ac8c69c9516eb5ecb279f01dca0cc5b1d33528f;
+  e1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa
+    7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2a
+    a947b0e3b6d5caa39dd7899d60cc739b86a306c9de07b826efe14d1565ae933c;
+  bf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e
+    4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac8
+    93c8e6eb9eb2a085c0fe1e424c031d75e3cb3924e6636a3d0fbd97a9057b1497;
+  61a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab3
+    83a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273
+    1a9447bbcab0bf9fa9d4f97b44df070a91e73465559561cf07bf66f253b74839;
+  117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d
+    2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976
+    19931b3731ce5cd2a6e0fd8db3528a01cf67f21c9f2b6536f617786536862f1b;
+  063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147
+    842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013
+    7814dc31116b923eff0567f1898f0dcfe5db31cea5f82d371c895b9cd0e1e626;
+  e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff20687
+    7de69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d
+    bf48e4fcb2685f89934fe3b4e1f093795e48c129192425f8d83df0a859982026;
+  52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfb
+    e61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c53
+    3c2f3e81bbfcfe08da13e35354b1bac0f0af0da35266c33c3a85c7cfa2ee849e;
+  6ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbd
+    bc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bd
+    975de7c5d90df79434ad560bfa1f2d3acb2bb268bad74a40f40dfb0b0cc55d80;
+  b75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cb
+    c0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3
+    778ec7881d07957cb956ee98b77f4771f0b354eee8ad6ed146dc9848bb4e5a15;
+  fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd6
+    6ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d547
+    b41eff7927b5a1646b42fe8e7f3404366196b47be1d22a51819727a2987a12c5;
+  56fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd8815
+    19165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9
+    eb4d497d39f0ccce56894c544b916a5a32aabb5e8470197389918e758cf5bcbc;
+  d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca
+    34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea
+    ef9fd1957ea0125681170f801a2ff55cd40c11f1d8d03e28a47d07e530518d8f;
+  51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae648
+    25ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e8
+    b48119d50954fe55c7cb531c051c858b91a2cc0be497434ac06f1746d05200b1;
+  8fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1
+    ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f3
+    417db866feb0dc25af3bbff0a733e5220044c6933507f6d68d651a77b3371083;
+  1b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb
+    84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17eab511edd
+    2093bb7f7243f7d09835512229a449b3fcfbebc4f158d1f360d61dfa33aba949;
+  b8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be740
+    88e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d
+    aadd61dcffddf277215a600d2a262375b40e8e8a00d2d1ee59d656ad63eca173;
+  907eab7707ca48ff5ba1ae93d16225d469de5747bc1addf5748729720a320fe1
+    4fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3d
+    1ddab3418f7c2e73138a161d9480144100ac8a8c453cea6cbda181416ce835c1;
+  a84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd1
+    8c374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce7
+    ac62a144b60cbcee96700e35a156c4ea04e8527600094b7c7c1fa57eb67c78c5;
+  57b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd651477cd7
+    26d6f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a87
+    6ac5d880e25effaad82da8efe77ed2245c9306d82e19c9b680b0a166b13db5cb;
+  33b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad09a5b8fa687ec3ba
+    d8e18dc2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24ed
+    6bc8ad093f2148dc06ee942ce06a6b6c41ad4fb2ae796f9351df4d7829d0b759;
+  fd9710b7bca91b612ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c83983
+    9c1b06319f687dbc68d9f07fd41ccb4f8cde8de201ec2680332bbded4883deea
+    7cdba7c767a1b2e0d8ea98db6d05d0e6dc5ec4add6d68cb3a0ed213ba91fb46f;
+  0b58b54bdd13c17ef292b0ded3caeb5e57fd21df10bc6186265ee6ea45907de6
+    cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dc
+    4d19278b4626808b203535680f24d55aa0bcf39b89221ccdceef29212f738776;
+  c73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945
+    d83f923e66b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6
+    e82546a97e4d982315567afa93cc9cfbed1e6a9a553fb7209ac3c0c8a0f7d2a0;
+  d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee7
+    8ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592c172
+    550b3822df20109989c3ad201218184ea69c16e7efc41e9ae40d163565ea52e2;
+  a5cbc19456c95c1bea6079f3867e52d663cb3884b2a0a8ff825df752423f3179
+    bfeb89eca385f20ddce5f1f23564672e370ffc37d400a31e8aac1d426ce10df7
+    b35239f297beda780ccb0168fadd0708fe02a09e29566b3cea47f8f1932321e2;
+  3c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6d
+    e738721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d9
+    5c8cae06450a234fd67621baf1be40de09a7ee05227b7cc527bfffb14c861641;
+  3d1f8fcc53574427767396322b3bf7d02cec05093696cec07591ada462271b1d
+    1519eedde0df37a330fe8c22ebd77705917b7e32ae88f45a34a8ba3037235e19
+    0d07975a21745840a9528f6ad84812f76d981c7cbd51d23295b0a4c77647955a;
+  a394be4d26ce47317d8087684456b4cfc5555e925e3e7b2ebc829b2d0505ea61
+    7b0ca9531bcdb96040d39040e632d562643ccb64286303040fcaf679e914eadd
+    b11034402f9178618471341a208717e0db49389cc10169da3bbfd18c0b155dbf;
+  c05af8843ce6a427b99a5dc266de31c09165237eeefe4b58cc034b9f099f0467
+    8c2a9da898b39324cd3087a651014f6796f9c4881d89e127e62221e47e57badd
+    a3115e01610e03d14a9aa231f0af30c2f864724a9b827bee723862a2da21f67c;
+  678d490c2f320ff8fb1c42761bd439f3e96dc0ed1d5b2169912af1a4e2c533c5
+    2ba3e8c71c23a089e231480aa63c484fb34bd522397f102cb8ecf4f64e329884
+    f8fb5571f45bfe48a3e0a32c0152f4cf9f05fd9b6df1b16c135ac57b53140b1f;
+  fe73be257a753b38200bc23f94a079bde2dd98d813655dafa15b85419d15c41a
+    5153cce5d0e8c8702db2ba11927589678d4f7b8fcfad4818c411f15f45230090
+    f0eb21d7c095cbb71ce2a6e98cd274161a006a321bc6516d92e292d4f9d80fe5;
+  3874f9a532ee46496ae753a2340af7b91f9632fc5ae71ae18b40de751ab6b676
+    1ca16434a9935e466e11c1cb072f32a59c313dba3db646ae909a096697d9a7b0
+    2784404b966884dd1be5778471a98b8cd9ffc6fb4cef97e9f828f5a9976519ea;
+  556463ff1126ebc43263391424d02739d0787e804d8f1dccf6c897a8a4843132
+    4324041b5302ccd501b538bd03d5cb5c90d1fd3f7d2be187a787032c79ed9007
+    7a286ff42bd536174d2d471c7edf52d76cc1e2149ae5e89fe7c527d1baf61024;
+  64ee4ce1d3fc042c084f7d8c0c48ad7d6f1eabd0fd1ec24a88f26734d5c8d92d
+    bd873a8fe113090d401bea4d28ff49f10ff593adc258e091abd31b62dd173515
+    c4cf640c91c885ead4d5ad0de5769f1bf2fc7cc928ddb20ecd77903e78d60296;
+  8f98765970acc6602da063aae01a2a199d3a4f37a5f062d216d2053a83b5d3a0
+    488ab0d2df631b2892cdfcf9fdd0f37de9ed67179aeae82fe00009428b297b55
+    fd32af281c32754a7cb4b70f0856a6a595d53df2f655dfb5d065813b658f6e49;
+  3230a6d917fa0c1a233c9ebc8a4cba45b20543c540fc1b9dbce078b87a1534ac
+    f03897b95a3f372e9f6c5a5f2ae44a7dbce9ba43a39089de20de70d0544b5151
+    d717a2d8e24c431d7322091c4afa9291e6b2f642164fb5dd41b03d63eb3991ad;
+  db0a16e9769e8f2fc12c7f839fab269a0056284a697ffd4113a1cf43b5d5bdce
+    2d86dead83f5a356e9106bedf908db61f1119f9700260ea9379cc7232184d217
+    ad5a3798580a21a9af3a14a20c498e9ba81075c0d4c771481da0b3e6544bb711;
+  158fee8ca42e75614739e9007f234fbcd86b0ad8f641a0449b6d9b0f99d1cb4a
+    57a4d6f987feb0ade90aa1d81c4f497b3734be301da3e25fe692629db57311f4
+    feca63faa55407c1cbe7ba36da4101ed6fc318162d0834ef6ea91095e6fbb38c;
+  22f3a1573f9e0553a23e96265e4326fa532d7136863e5b4bc6c99ade3d4eb23c
+    acdf6e42ad8ca13187eba1532920ba31582b3793b05fa65e9f80c5814b91f4d3
+    c9ddac65e7d93033570d39fc200ea11df6f56cf19994e791092cab78342f8793;
+  c581c7b16c46b484859c6d19eebaf124681aa3be9943307fa4ef095ef8e7e50b
+    703dc0420e74227c9351366ef8e98e1e24b48aa989dbb8d0f10471ae5428a601
+    f1e437fdbee29a5838d58d6ca0abd51bf3fe4bed82ea86f5e3d2e8effa7dbee9;
+  2fbe4f5cb2dab2863e574842cc0b3774e00dcfa63b0db1716c7e916a26fc2e19
+    8f8db63ab59955989497782f16c5816270ef3fbe4ea22f484ddc12ec8f4bdbd6
+    c8721ce2f69e7d5d6fc5746fea4185ff8a7d296b99bcc17bbbad3e7036053bcb;
+  ebdfbafb21fcf5427dbee5f95b53a0b4cb6d7c128b79f4657895f4b0ba518dd6
+    1436140f20d40224baac3a602da83cb254a7e03f052c63c1f3f00f301cc944a1
+    f3298d9cfbd5fd3a98e1ecabe8a2aac82b1b54f2f65f09d7cf3bcd9ca8bd2bcf;
+  789133bb8048f07dc123f2ca7e20c83988e4bfea6d561ab5aea542db544a1437
+    6d5d52f7265c7a8d2fc4feef99b9dba89eb472f71d8eb5affe900d776e4cf74e
+    795de908ed1e3149d3e92fc4d2fb56c47db72b54097702f360c3de4363a1b38c;
+  52b6c86db981143082735c6473a86a5da3d2e8cbb8602ebbaf08bf9315fba15f
+    46714bfd2c8312fb5744dfe84615ddb93f15360161f2efb1fc39b8b6ad97427d
+    9e96a1dd18f2683365cb98a46a9cb8bf49f1766ac86eddec4a87dfa3f83339ce;
+}
index c0b928d..c51e842 100644 (file)
@@ -24,3 +24,245 @@ idea {
   729a27ed8f5c3e8baf16560d14c90b43 d53fabbf94ff8b5f 1d0cb2af1654820a;
   729a27ed8f5c3e8baf16560d14c90b43 df8c6fc637e3dad1 29358cc6c83828ae;
 }
+
+idea-cmac {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    2a288096bbfd3366;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    2f7fb9948ff504c6;
+  14ad568f86edd1dc9268eeee533285a6
+    ed810c9b689daaa9060d2d4b6003062365b0a54364c76c16
+    d077db9252901d26;
+  0f11896c4794846ecfa14a7130c9f137
+    120634c9519848a877ff77bf79192a5b50ade5
+    c17895f93dd73a8a;
+}
+
+idea-ccm {
+  e4bef260d7bcda163547d348b7551195
+    e77022
+    ""
+    ""
+    ""
+    42939dba;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    568f86
+    ed
+    ""
+    ""
+    3facc6db;
+  d1dc9268eeee533285a6ed810c9b689d
+    aaa906
+    ""
+    0d
+    7e
+    4f9519dd;
+  2d4b6003062365b0a54364c76c160f11
+    896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff77bf79192a
+    5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba23408540
+    53683900f166af9bfd8a3e46e63e8e38af27b1c46816b6ae
+    5e8bd4980b4efd9c;
+  6a6136512061f7080cc07df0591d8fa2
+    1f2dd88374
+    d8cde8e160ad10997a21635c6d62c9269029df
+    3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e5
+    ea20e70bc5af22eece46f5b4adb9148a716a08fe014fd8e603cbad4b05
+    df275b1d8b433882;
+}
+
+idea-eax {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    2ed1b711b35815fc;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    ""
+    ""
+    ""
+    e16c2e8dcbe82476;
+  14ad568f86edd1dc9268eeee533285a6
+    ""
+    ed
+    ""
+    ""
+    d71cbbb104ef47b6;
+  810c9b689daaa9060d2d4b6003062365
+    ""
+    ""
+    b0
+    93
+    f9fa771344725555;
+  a54364c76c160f11896c4794846ecfa1
+    4a7130c9f1371206
+    34c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f33
+    7f29549e6b0d27a4ba234085406a6136512061f7080cc07d
+    cfcb5b76771f439b7e31a9503bc42213efcb50281711c0e0
+    e70f4193b0a49031;
+  f0591d8fa21f2dd88374d8cde8e160ad
+    10997a21635c6d
+    62c9269029df3e6057acc87638f508046733d9
+    ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50
+    dfd640ccfb02298e9bdb44464e210bb5039e2fcfdf99a07198b5a41744
+    8100822295ddbb3c;
+}
+
+idea-gcm {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    b53b4af5791611f9;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    ""
+    ""
+    ""
+    5d33a50146fc1873;
+  14ad568f86edd1dc9268eeee533285a6
+    ""
+    ed
+    ""
+    ""
+    476a48223872d6dc;
+  810c9b689daaa9060d2d4b6003062365
+    ""
+    ""
+    b0
+    d7
+    e7f3f045a67219ca;
+  a54364c76c160f11896c4794846ecfa1
+    4a7130c9f1371206
+    34c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f33
+    7f29549e6b0d27a4ba234085406a6136512061f7080cc07d
+    35242bf91114f81e19e23a3ac1ccd5a9d133f097e1e32358
+    d7871555c86f43c4;
+  f0591d8fa21f2dd88374d8cde8e160ad
+    10997a21
+    635c6d62c9269029df3e60
+    57acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dcea
+    badb12a7460b5d77826a7f419823376c332f6816280031f04aaffa9b92ed8c83e9
+    ca45ffd7a56d9250;
+  a7b1cc49ae1d50c38201a894476b3f10
+    2b752eb9529533
+    966f27043eb621b7f65b000961040ef2f9b2fc
+    5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18a
+    8508e77f69eba79e7dd8b644ed31dba2f0eba90d09b1170ec17caf72ee
+    6c86db8654126e19;
+}
+
+idea-ocb1 {
+  e4bef260d7bcda163547d348b7551195
+    e77022907dd1dff7
+    ""
+    ""
+    ""
+    6c1f67d06c352235;
+  dac5c9941d26d0c6eb14ad568f86edd1
+    dc9268eeee533285
+    a6
+    ""
+    ""
+    461d68824249a125;
+  ed810c9b689daaa9060d2d4b60030623
+    65b0a54364c76c16
+    ""
+    0f
+    a4
+    f29d06f84026383d;
+  11896c4794846ecfa14a7130c9f13712
+    0634c9519848a877
+    ""
+    ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27
+    02d1b52db3743fe74199d2d47c7b9a5b40be540fd3305c63
+    95db9f9e14cc4137;
+  a4ba234085406a6136512061f7080cc0
+    7df0591d8fa21f2d
+    d88374d8cde8e160ad10997a21635c6d62c9269029df3e60
+    57acc87638f508046733d9ff61cdbda3b3e9878731ebfedd
+    16241a876ecaa1787050ae161dc95e08b3c9f3f32f4c28e6
+    4c3a1cbf28420f74;
+  4705e505da1435dceaa7b1cc49ae1d50
+    c38201a894476b3f
+    ""
+    102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa4
+    fc37976d31a17e5c9184a761ade81acb146791248da7073854564e80e2
+    69afdd038f3f443c;
+  50727a9b542cde52ebfda19d0ccc520f
+    215eb57bb3a4f3eb
+    bbb18ac6c95a97a48030370c33d090c54215ab
+    d6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff6310
+    ca23f10e82cad6a83e29296f3040d728e2c19d8a70da3c85bfd6392e83
+    13a82d59cedb63ae;
+}
+
+idea-pmac1 {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    487cb8bbd49fdf9f;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    61e71d184211ae2e;
+  14ad568f86edd1dc9268eeee533285a6
+    ed810c9b689daaa9060d2d4b6003062365b0a54364c76c16
+    2a59b4037636f6e9;
+  0f11896c4794846ecfa14a7130c9f137
+    120634c9519848a877ff77bf79192a5b50ade5
+    64b5b29952d302fd;
+}
+
+idea-ocb3 {
+  e4bef260d7bcda163547d348b7551195
+    e77022907dd1
+    ""
+    ""
+    ""
+    d4146d9749c5b4cc;
+  dff7dac5c9941d26d0c6eb14ad568f86
+    edd1dc9268ee
+    ee
+    ""
+    ""
+    91344823fdca261a;
+  533285a6ed810c9b689daaa9060d2d4b
+    6003062365b0
+    ""
+    a5
+    32
+    bd1e855f2cfab6a4;
+  4364c76c160f11896c4794846ecfa14a
+    7130c9
+    ""
+    f137120634c9519848a877ff77bf79192a5b50ade5d9cd73
+    9de3e559bcf16005a54f07a11b791f0c87486d260cd04d40
+    0f6c004bce2fdfa4;
+  9a3d1f337f29549e6b0d27a4ba234085
+    406a613651
+    2061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62c9269029df3e6057acc87638f508046733
+    07d9e965ec0f32d6ba5393c0504a9e274d18fbb31e705f7e
+    d1f5621c6fa3f2c9;
+  d9ff61cdbda3b3e9878731ebfedd4705
+    e505da1435dc
+    ""
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043e
+    a51612481f15245dfec7f8e1ffa9bc47788140faac776d8fce971d2d96
+    2030845d5729cf4f;
+  b621b7f65b000961040ef2f9b2fc5fa4
+    50727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b9
+    cb28e83ecdf27012219f655bf27bb37de417f09f4337a92bfe5feb3da2
+    cc56a222f733795e;
+}
+idea-ocb3-mct {
+  16 81bc29159fbaf9aa;
+  16 fb5ea26d7558;
+  16 1749134c;
+}
diff --git a/symm/t/mars.local b/symm/t/mars.local
new file mode 100644 (file)
index 0000000..126fddf
--- /dev/null
@@ -0,0 +1,922 @@
+### Local tests for Mars.
+
+mars-cmac {
+  60d7bcda163547d348b75511
+    ""
+    35a1192271ad4f717fe9e5ce36550ccc;
+  95e77022907dd1dff7dac5c9
+    94
+    79d05cda7236e8a9038a3e87d6dd590d;
+  1d26d0c6eb14ad568f86edd1
+    dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1
+    04093d618ec9a9f929abceba0ea5d6a5;
+  37120634c9519848a877ff77
+    bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8f
+    0436ec24f98dbf64019710d997ca79ad;
+  a21f2dd88374d8cde8e160ad10997a21635c6d62
+    ""
+    51be3cd07c56c6f821f8261bbf55fa38;
+  c9269029df3e6057acc87638f508046733d9ff61
+    cd
+    c29104d9daa7eb4abadd817b6890df83;
+  bda3b3e9878731ebfedd4705e505da1435dceaa7
+    b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b54
+    6b2daa274c101b703e7cca9de8608b13;
+  2cde52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e2
+    de39e39bd3108b76ec6c4c68a923ecfc;
+  7fff63102758fe2b
+    ""
+    db668c175219b873ce67bfee1bf797dc;
+  69ac26afa3349829
+    b9
+    d8e6cec8197a0d3b02b973e0b8821048;
+  4586306fed54154f
+    8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42
+    1fef4ac7afbf6a5b2e8c6eb271a6c73c;
+  f70800df9fcbaca4
+    8b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66
+    bdc7b92cd3b6b1f19165fa1452144363;
+  f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b
+    ""
+    baf27c811850b45c6165fa5f28c558ea;
+  6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    b9
+    c838ff7ffa0b020de74cdf1bc6d9cb1b;
+  aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa92
+    3834f582405017c74df2a58f50896bbe;
+  1451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e61766
+    9c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb6
+    797407de4940048d366f408567a0b4ca;
+}
+
+mars-ccm {
+  60d7bcda163547d348b75511
+    95e77022907dd1dff7dac5
+    ""
+    ""
+    ""
+    d9863a89;
+  c9941d26d0c6eb14ad568f86
+    edd1dc9268eeee533285a6
+    ed
+    ""
+    ""
+    291967b1;
+  810c9b689daaa9060d2d4b60
+    03062365b0a54364c76c16
+    ""
+    0f
+    f7
+    b93f6b02;
+  11896c4794846ecfa14a7130
+    c9f137120634c95198
+    48a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8f
+    a21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731
+    9828628579a7dd487f473888502c5c84369b7c3a4c760eca290e95d6ecc9f0eeff551a28e55ab8f07a3b3058263e6590
+    232a8e27bf269e09d6ca6691858e03d3;
+  ebfedd4705e505da1435dcea
+    a7b1cc49ae1d50c382
+    01a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52
+    ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    983ddf84477174e42ff5e4d86e34a4dba2cda48b0d9cc34dca96cae438508ea257ae6e4d0f34e6c38612bc4044d30e3f44550b49eb
+    aece86043084433dff242601596ec036;
+  aee2b03fb648e27fff63102758fe2b69ac26afa3
+    349829b94586306fed5415
+    ""
+    ""
+    ""
+    c9700d28;
+  4f8f28523c03d4de1600157846b710ee72807a22
+    19bfb474fd71d891f24bb6
+    5d
+    ""
+    ""
+    86ac2560;
+  1563259f9eb53b571ea629c54d57dd2d42f70800
+    df9fcbaca48b77dba18919
+    ""
+    6d
+    ce
+    7396d0ff;
+  1ebba10b0467cb9fc2712a199e533fa9156308cd
+    ec3f768281e040a9b9
+    a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe83681
+    31115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd4
+    2e78ed36197ee0fbe02aaf850ca07cef75d83137dfa779a043f43ad6207cb71df53b3bc72ec31947217f1131f9a7219f
+    38d70bb7304992be2073bd3ded9589ad;
+  1e72d7b97e23e6eabdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012
+    e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1
+    af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16
+    91a4428db21b6870c8bed64235a802123bebc572b852321902ffa4e1f9197eab5a4e2d6e37587f493a77dc78355556ecf4078f6963
+    2ca5ad4c8de48446dacc9ef0f8ed8ac6;
+  c2e815f422cdf0c8
+    e30308be3c31e6bc58c0b7
+    ""
+    ""
+    ""
+    e55b1e3d;
+  cadcb658b970e474
+    79a684b5aefa69a4cd5214
+    7e
+    ""
+    ""
+    8e9f4277;
+  d12ca986981a8744
+    98ad0abef8bc4fcb70e27e
+    ""
+    98
+    da
+    94060c3c;
+  ef1f0446b42fb144
+    d44b6d00f06dc188d4
+    72a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf439
+    66eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb
+    a845f5b258e7b48dfbf165716b84ab9d44a6fb31ae2db3969ab9236937b52c81e38427414b61004125cd07ee50001947
+    053ae04c909fb9c1202dc16d15d93890;
+  824173d7634c0422
+    6f30cbb7f0e4a973a8
+    cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f2
+    94b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1f
+    7bc1f6ba933f20ea05b7b6eeed69b99dfb31c21c77a46690e151e756c0af9555851d17700b27ac7d1104a4ce197bb4d3e5d596ed37
+    5b81abd7dea2c26dfdb3dd4fbb3679c9;
+  f6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c8
+    4cef64f6c9b53bf8f957f4
+    ""
+    ""
+    ""
+    5702f7ae;
+  b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b
+    1abf91b0851e5ca605ac84
+    51
+    ""
+    ""
+    d5c802e3;
+  399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41
+    cf9a05c7efedef3401539c
+    ""
+    51
+    df
+    bf7584e3;
+  d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92a
+    dd9589d1f5c054b2d9
+    83514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d558
+    9bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42
+    332eb9ba36705464ae13b42c953572119f3bd26d623fe066fa9eb42a3aa5222fc7a39367b997e903b8471ded7b4e1250
+    b10fea22e3e1c7cbdf334e2e66986200;
+  fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9
+    aea3ccf860b0009740
+    763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3
+    aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd6777
+    2efcfbce25279f45598c9d5dff6821a9b6bdea37fc7c376e8a65c0d6182392b15de9832a2477f5c446b3028872892061a213cd7f51
+    e44e2d82e160ef2cd7d28cb80fc74194;
+}
+
+mars-eax {
+  60d7bcda163547d348b75511
+    ""
+    ""
+    ""
+    ""
+    783e4c5710aa46926fa54c1810e7e73f;
+  95e77022907dd1dff7dac5c9
+    94
+    ""
+    ""
+    ""
+    1f777486cbacb84834939cf4312ba37f;
+  1d26d0c6eb14ad568f86edd1
+    ""
+    dc
+    ""
+    ""
+    ea4ee101b3dfc447826294eb9e188f93;
+  9268eeee533285a6ed810c9b
+    ""
+    ""
+    68
+    32
+    36ad1e9dd22bc536eaf6e1bf4148b92c;
+  9daaa9060d2d4b6003062365
+    b0a54364c76c160f11896c4794846ecf
+    a14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a61
+    36512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f50804
+    a2b79ebe3a643e16a26496a833169c430350296feff84ab5e97a837f27c1cebf042c077d8ea23697c1101fcd3880025e
+    3e081ad4715f6b2ccf59ac6cbee3ecbf;
+  6733d9ff61cdbda3b3e98787
+    31ebfedd4705e505da1435dceaa7b1
+    cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450
+    727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b9
+    e32192ca15a8b60348fbcad6bed31fec7d8930fb015efea33f827a691a245be1b056f237da85e63dd7f6948a583c5040b24eb76747
+    c69cdf6b68ff0b95fd49073f69b24673;
+  3bf4f2aad2605faee2b03fb648e27fff63102758
+    ""
+    ""
+    ""
+    ""
+    8197dfbcc4259667affb2610283f7cb5;
+  fe2b69ac26afa3349829b94586306fed54154f8f
+    28
+    ""
+    ""
+    ""
+    4365d2d730280b57ebdd628d574db279;
+  523c03d4de1600157846b710ee72807a2219bfb4
+    ""
+    74
+    ""
+    ""
+    90f8bb6ae36b77e86acd862d626e3e8b;
+  fd71d891f24bb65d1563259f9eb53b571ea629c5
+    ""
+    ""
+    4d
+    4d
+    e0c975ce580afac6215a31f89ed849f5;
+  57dd2d42f70800df9fcbaca48b77dba189196d1e
+    bba10b0467cb9fc2712a199e533fa915
+    6308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d
+    95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca33852
+    68cd20e274b1dfc8045c4f1a2a862ae38adaf6f1b4d37a869e1ca4dce62cffab0e767e21b7980a7a6923a4e6036e261f
+    ab0fc228a30f96fc6af0af7ed3b2ca23;
+  7ef19b09c063c46f88de9fd41e72d7b97e23e6ea
+    bdff3bcd211499268878dbf30f1dad
+    89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aeb
+    fa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d
+    2d5f33737604edbff4256e1803d85fdf97b1d11755a7c54907279c926103ad6dfcd2a49bc8f09692af0225e58727302883110a1d9e
+    66d2add5b20b0083fe707359e14b9a81;
+  264a7f16cb16c2e8
+    ""
+    ""
+    ""
+    ""
+    bfd46275d139ade04b23701a58f03996;
+  15f422cdf0c8e303
+    08
+    ""
+    ""
+    ""
+    70b1aefbf33858867e95f8420409cc5c;
+  be3c31e6bc58c0b7
+    ""
+    ca
+    ""
+    ""
+    06ed7dfc19e244619a78291ebfe53e1e;
+  dcb658b970e47479
+    ""
+    ""
+    a6
+    b3
+    50a2cbdf827bdd413fc402b1bd4d3cad;
+  84b5aefa69a4cd52
+    147ed12ca986981a874498ad0abef8bc
+    4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9
+    eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851
+    1717ca0fe9a9f844e7b875383fffb728907e4381ca81aaad7d07ae4559463a25e3eb4eddc2c1eb47ac009050404e125a
+    54681d8a74c5240d91fedda335ba0106;
+  bc2810d858cbbc84
+    24d126b807e6daa089c3f9099c5ffb
+    824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3f
+    b90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b
+    b49998808ffe0713f231dc44d5fefd7b091d037fa88a0b00fa7df49a9cb715fa11272ad859a1b6bcd40fa4a618d4b9694a98800fe1
+    cfb2cf5bd57a0bd2e0b6e4766c85ee66;
+  9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458
+    ""
+    ""
+    ""
+    ""
+    c182f7ff71663492c075606138691990;
+  cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a
+    3e
+    ""
+    ""
+    ""
+    bfd6579cd96ad44cd5202593235be036;
+  8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605
+    ""
+    ac
+    ""
+    ""
+    b0aa4fd770b15ab6cf76338e9e4ffcc9;
+  8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529
+    ""
+    ""
+    ee
+    1e
+    d1aa1cfbf63991b5a87719a436f3bc15;
+  41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a
+    5718fd25014107c8e7d715a92add9589
+    d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a3
+    32ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d
+    6c1092bfaaba31b04c5ce196bd217368bbcb33fabbee09d16cc36d6047594e2f33f6241828d17230e69561355af84d2b
+    9adaf12e17b54bb121e92f5262a03d46;
+  2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e5188
+    1e99027b8ab9aea3ccf860b0009740
+    763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3
+    aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd6777
+    64f2ee469fb1577675427113e478b43ab8915dfc5a3370b0b55dadd51f1415083831183748bbbd393ee54171fa12a112addea5bffd
+    4172000e1d04402689bffffdf46cabac;
+}
+
+mars-gcm {
+  60d7bcda163547d348b75511
+    ""
+    ""
+    ""
+    ""
+    ebf333475ccfd01e22434b02b7356886;
+  95e77022907dd1dff7dac5c9
+    94
+    ""
+    ""
+    ""
+    1f643ac59e0fe29a4c1a84833c1093b9;
+  1d26d0c6eb14ad568f86edd1
+    ""
+    dc
+    ""
+    ""
+    e8ed5ca386836f0fde3d8def53764182;
+  9268eeee533285a6ed810c9b
+    ""
+    ""
+    68
+    c6
+    0a84b3ea1725580f6ff197fc09ad1d97;
+  9daaa9060d2d4b6003062365
+    b0a54364c76c160f11896c4794846ecf
+    a14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a61
+    36512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f50804
+    22ebe7296754751f308114594df1ce2c029a959eb46639dda878d75cc411f58924dd49d15b515cb32c987716b9668fff
+    9a65ff41da556c3b4ea0154dbc6a7432;
+  6733d9ff61cdbda3b3e98787
+    31ebfedd4705e505da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b75
+    2eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97
+    5ac307a7ba0e8c3f15b3da71b2dbe231914d92040e6099060e12312f940f512a4bea4f140ffc99e37cd4c004fe70fd9afead2070b93e171944
+    3e3a39a40c14cf4455054df3dc812412;
+  a48030370c33d090c54215ab
+    d6b3ad54efc9a38378c5b93bf4f2aa
+    d2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de16
+    00157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189
+    0c0dc2d9d390c165b844a4fe302c9468dd61b989ec85e415c2e66a02c6a9e88e6c4b29b59526b3bba15ac8c7c773fad8cd346313d5
+    b66ce563af3c5adeb147f05f2a1332a7;
+  196d1ebba10b0467cb9fc2712a199e533fa91563
+    ""
+    ""
+    ""
+    ""
+    a3752b6bc192c30a8b4a33090b82c8f4;
+  08cdec3f768281e040a9b9a222bd689aef66f530
+    6c
+    ""
+    ""
+    ""
+    2d7f085e88e212c1d5a7470222846f6d;
+  eb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa
+    ""
+    6a
+    ""
+    ""
+    afd0596615ac5995f94a4c4933d7bc2b;
+  5cfb0bad7d95214ade49cb3b6f5fe8368131115c
+    ""
+    ""
+    03
+    ac
+    06c5e4184cedd818df6808aed1cbaca3;
+  7ba323fe1dc8151784873f0eb5b647da6794c18b
+    5337685a96ed65b9aca338527ef19b09
+    c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d2
+    2bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d07983
+    41ed7b09be9ff9174abf78851ec6b7dd1de6abae054b330e761068fcb38c10e658d4a4dcccf87c9bd972a7c3736681e7
+    87c051ef30fb9d6b610ac3d8b367d190;
+  91805da08da3aefc5f8584b7c5e617669c0f16e3
+    9815d4e9cfce3ed1ecdf3d26
+    4a7f16cb16c2e815f422cdf0c8e30308be3c31
+    e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00
+    f08e36ab5ed57342834832ae777155f3b98a75495279de1d647d6cbe54143a9ccd11a1394c37aee68c4214deb21134425a11084387c60b3af4
+    4a3532e7462571f4c0aa720877fcc127;
+  f06dc188d472a784e0c6f21195a3b9f4ae985511
+    265febd11c164720eef9eb1c8dd0b0
+    0951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851
+    bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff66
+    0dea7dfec76fd70330daafa91a42de22cb7d9ccb8f762fb36eeb5cacf96cad8a5972e163c42f0ccffceab82352f7b357614c058b2f
+    8e46584fadfee6bf54b6b3df1127e528;
+  9c732b58db8f48af
+    ""
+    ""
+    ""
+    ""
+    97b6cfc2d51f18dbfb036aead20cf7c9;
+  65f7cc9e3fb90e17
+    21
+    ""
+    ""
+    ""
+    e660c51ce4935fb6b0568b9da21fd6bc;
+  b730374ffc9bc597
+    ""
+    f5
+    ""
+    ""
+    029a8fbbcffd6a6657ea08e6f8563c5c;
+  6ccbb2f294b38766
+    ""
+    ""
+    fc
+    73
+    8a51e96b7e49dd61bf505d6be05880c1;
+  69f6a9f2c0945ffd
+    505003cc0cae9ce021a5f1fa4ffa9154
+    4485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd40
+    9b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70
+    51af1a674261ce3b602216b7be5490dc29b5c0fc13111ef312aee59aa415455eb45ecb08971640295ee6083d336852ff
+    033c89302140a07d7ec18495ac6e04de;
+  e04c091d205cdad9
+    e9a79b1abf91b0851e5ca605
+    ac8451399587011677508a15dde524af3e2bee
+    0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718
+    1322a51e98047b8ab460b5862ecb72506d86347ff23da7c246c7412e66f778c44fcac56086f6233cc65342b25825c27447162c75c4f4d47e77
+    d1c84ad7d023b7339eeb10cf9d4a54b0;
+  fd25014107c8e7d7
+    15a92add9589d1f5c054b2d9835146
+    05ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5
+    d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b66
+    7d49e4c21966171b11dcd2557bc759735b6a0f8883869a032ff7e3b7300f6c177a17c78de29b7dd1fb60dcd83df08d94b4f7b203fa
+    9e558cfae2396ef731781539964cb64f;
+  9ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3cc
+    ""
+    ""
+    ""
+    ""
+    d7edfedbfaaa00b83910524a6a72a0bd;
+  f860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c
+    1b
+    ""
+    ""
+    ""
+    9b47dca7222907d7728d60047341be6b;
+  9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a30
+    ""
+    8b
+    ""
+    ""
+    4d7ff706428aed21fed40ba423e497f6;
+  a60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a17
+    ""
+    ""
+    0b
+    ed
+    513db06c53e14e17a0a6a2358c63eb84;
+  66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861
+    a8b33779f09e7a10fc02a8f48afa3080
+    ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac27311
+    7b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c88088476892114
+    1cabcdd7bd2c878d0d509527aba73014be8fda187aad0fa6171cdf7b40611f6e0436653ff03bdc3540fc240fbf2edf11
+    4747f36bac04dfc0d594803a8b5f7393;
+  50ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785f
+    e426a5a0e80f678d40414784
+    2941feeffdc2eb44dc8c0d5e8f444f7f4e0c89
+    3959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa7
+    83be0a213ffe127c49ec5352ec0f5542abda27387079f4e8f6e056187eb8e7afe34ef415383f54eeb5332137ca5407e3bb19019796a375286c
+    03d0ffe3b26614eb375f0f9043d69cfa;
+  76945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8
+    f08ce7cee4758a386a9943e97dedfb
+    e61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98
+    edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bd
+    9f02629363a56a6e8067f76d0df265f5d1d4774c129186fd96e0826e4d5a6fd643b6fc7e484caa72575f7774f8d7d55529c816b3a8
+    77d7548dfeed0ca41810c69586ef999d;
+}
+
+mars-ocb1 {
+  60d7bcda163547d348b75511
+    95e77022907dd1dff7dac5c9941d26d0
+    ""
+    ""
+    ""
+    4653e79c83c9692f680b6ab67aa4cb1c;
+  c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d
+    2d
+    ""
+    ""
+    9cf228b3a0a873d910ef08325178c9ce;
+  4b6003062365b0a54364c76c
+    160f11896c4794846ecfa14a7130c9f1
+    ""
+    37
+    7f
+    3194ce1f7b3c055b5c465e9449713d73;
+  120634c9519848a877ff77bf
+    79192a5b50ade5d9cd739a3d1f337f29
+    ""
+    549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c926
+    da19eb03799876ac0c7f25bbb54e051149623d839822c5305b2348306fb687a95debfb6d8463b8f61eff55879a8e4854
+    c9315ab551796c3230de8d1b783e41c6;
+  9029df3e6057acc87638f508
+    046733d9ff61cdbda3b3e9878731ebfe
+    dd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040e
+    f2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215
+    e6fffaeff62574ca11871e98539b5d6252724476ceaf2e6f7649e25df4c7fa2d1168bc6913bfcabbeb65cc7673d64445
+    aba7309b9f99d4d595029cb68eb9dfef;
+  abd6b3ad54efc9a38378c5b9
+    3bf4f2aad2605faee2b03fb648e27fff
+    ""
+    63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb6
+    41d2c5f2747177da8fb403142b15976849d6092a1f30a00a7dd86dfeae5e9a4d37a2b63ab07ee4ef461bb0c5a0ccce42767d08bf87
+    a5990263e713d60c619a4c8e15b6b3c4;
+  5d1563259f9eb53b571ea629
+    c54d57dd2d42f70800df9fcbaca48b77
+    dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f530
+    6ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc815178487
+    996f3de0c448f6bcc7a05966caf6b55b9a6e89038b7b1dcf0e227940a481c7d01a8deb9ab18c66e6e40f77673084abf2237348d737
+    12639c6038c9de5dac44e56672cb55aa;
+  3f0eb5b647da6794c18b5337685a96ed65b9aca3
+    38527ef19b09c063c46f88de9fd41e72
+    ""
+    ""
+    ""
+    2a302865877be6802bf265563679f4a6;
+  d7b97e23e6eabdff3bcd211499268878dbf30f1d
+    ad89d4b9b12012e4713df46795630e79
+    52
+    ""
+    ""
+    e504301acfb3dd72388b857ee7030835;
+  d22bb02d7100b8b649377d20a8f083455b663e4e
+    e1315f3c8f2aebfa921451dcd1af5813
+    ""
+    b7
+    ae
+    e2242b2d76d0f58177d422c14007837b;
+  0d30ce2f1fef6ef315d0798391805da08da3aefc
+    5f8584b7c5e617669c0f16e39815d4e9
+    ""
+    cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4
+    289ee6d05f1e2afadef55a9be57142c9434db665577e5e471466dcf0cd8dcee27b8337966c5f1a45a88f87801fc4ec61
+    de6956f5723d140cb3147978cdaaded2;
+  cd52147ed12ca986981a874498ad0abef8bc4fcb
+    70e27e98ef1f0446b42fb144d44b6d00
+    f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed0045633185
+    4bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3
+    6887543c971afe587132ed940556ec6275f8e92d4f94bcc8f31ed297ebaa6757c4353fdc1f6bdb1a870c22336f825a96
+    abce9a9e9c6f5d09e99c93d7eadfede3;
+  f9099c5ffb824173d7634c04226f30cbb7f0e4a9
+    73a8cd190107314717a77456f3ff669c
+    ""
+    732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1
+    f449b1339ac9985a1c4b342d1b0a5c41f15b8b2aca90c12846c792ae42057b3fd7b41111c8db756adf5a2ef5e1546e57fa0243cfb7
+    ba66681acccec14ef865b02f3c39b3f6;
+  fa4ffa91544485f1a1258b2b9b8f0911e32d65cc
+    1770a18cbfe6effd1ff6778554acf127
+    0485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf4
+    3e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a
+    7e1008b868fc1e9839963cd536e425796a5a83fbabd727f72bdf86fef8cf16929a5d491a4657a4228a19e366a213f820cda50268b2
+    3f0cd60dee1bf4bedd8415232e0e5a2f;
+  15dde524af3e2bee
+    0646541a42c2ecccb44d65bad397abfa
+    ""
+    ""
+    ""
+    158bc7dac7095b407e95a345ec6362d3;
+  f529ee41cf9a05c7
+    efedef3401539c51d2a90bbf7f1bfc33
+    8a
+    ""
+    ""
+    8bef95789b98fffc2e3a3324237b03c4;
+  b0ef5746ea8fdccc
+    d213e33f7e8a5718fd25014107c8e7d7
+    ""
+    15
+    bd
+    a88cd72e0e1e676c5c011dcbc14d2e46;
+  a92add9589d1f5c0
+    54b2d983514605ec590294a319b98020
+    ""
+    68a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e
+    6ed48f6abe15219da489442825e579452118ad3fef19d76292398eaea3a27d2cf358a5a1dfc1810c68b5e17db646d4d3
+    b19f3b616690535f642ae58f4263880c;
+  6b7ea2725cb2dac0
+    7ecde95759ac46fee6dda7abc8ad68da
+    ac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9ae
+    a3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1
+    f5c8dd655912fff44348c17cc0a0178fc55bbb12f4af3a017bc8db8b27c168d1feb19bcdd00b8f738adb541425412da2
+    820fbdee601293312a0756571cdd2389;
+  f6a7a3aa7e740da9
+    67828e3604b35b15ffaa6c36800d9645
+    ""
+    563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c39
+    201b87f6e406e13217b302fb759395dc0aa43b22b175472f45de5349ad46fd04c6fe85eb5c553432dd49fc279f668562f705ca3aa3
+    f7b7990d4d35c703d03b18b009bd6a6c;
+  73accd56f6f24e33
+    958b8c2e2352fd61e4fa8fec816ac861
+    a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc8
+    75fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f
+    1bc1cc2a9d971ffd42de07dfe98a00df3e83baf24c8a7b658eaaad1b61726d6b9aa527fadebb284414e9d75eadd23274710de7818f
+    294968c6ea337be16fa4b02cdfa33e50;
+  9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab6
+    1f813e28a1397a7974a1d7f4220c785f
+    ""
+    ""
+    ""
+    91db1563a8a1d0f60253be719e1e41f1;
+  e426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc2
+    3a7bb40e7e0013e5150686d2301b43a1
+    5a
+    ""
+    ""
+    83e94ddd60fb2b811905035945907c5d;
+  84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776
+    945948d1b8834df2196c92ec1718dcde
+    ""
+    ee
+    b2
+    0d56aa6e43ad24239efcfcd726927fc1;
+  0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e73
+    7882cd09c2b9a80f34c0fde11c2481b1
+    ""
+    1fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1ccc
+    b8b85de994a54ef5dbcbd85f5eaa88e2b2464262a53859300232029741b167876b6d3195c95957d5600e31de5f275da6
+    e69278334c8133c3710564526e2016f0;
+  ada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d9
+    21056b7de74fc9a9b37154ce6c0b3961
+    79d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d
+    4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59e
+    9e1e7295f6bb0cf520a77dc6bf4cae9411c79bf4d9e6a2a862efd982f4525bdd026b7ce5bb28b46bdf4bc4eb3e8e9675
+    d5ca1cd9e51f5441912d15626930b798;
+  d034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a
+    22d9fd881519165eb9d85197a21cc34a
+    ""
+    c0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca
+    33c0fb24bcc9948f79e7257d8816767fd83a862643e0e31b1ecde6dfc39523dbb29b396435eae70c7658cbb9442c457805713c45da
+    b0b7b3760231dd8ddd9a6378e27fadc0;
+  34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f
+    938f6daafbd656445a09898eaa96ffc3
+    d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538
+    e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a95
+    da25756b3f6d874af5fc62eb4d23153e0f42f476f6ef83622e6b704eac2b1c0ffe419780e789c457c51fddfda8c999b9a4eba0ae59
+    8c06ff6ecbcc83696b7a3ceb00819fef;
+}
+
+mars-pmac1 {
+  60d7bcda163547d348b75511
+    ""
+    88349068f0361feb5ab861422204a1fb;
+  95e77022907dd1dff7dac5c9
+    94
+    68e53c106eac08332168b9710686bde0;
+  1d26d0c6eb14ad568f86edd1
+    dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1
+    e73b3d7d64f57c88e3d08c79531304db;
+  37120634c9519848a877ff77
+    bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8f
+    155e94d935999190f3c4707830a1627b;
+  a21f2dd88374d8cde8e160ad10997a21635c6d62
+    ""
+    25767cba62b028dc2b28890f20b71457;
+  c9269029df3e6057acc87638f508046733d9ff61
+    cd
+    8e847f813725a45c86f09bbdf9d3984f;
+  bda3b3e9878731ebfedd4705e505da1435dceaa7
+    b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b54
+    0f6d60ece48580fae8d7914ab7194ccd;
+  2cde52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e2
+    922c357cc72223d59ef79018aa0fce6d;
+  7fff63102758fe2b
+    ""
+    0b46ed47aa8b8d1c15b9a1be5116955a;
+  69ac26afa3349829
+    b9
+    779d971e639e3f8c5e8d280d78a56a14;
+  4586306fed54154f
+    8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42
+    9594bd5550eddba1050516976565ee32;
+  f70800df9fcbaca4
+    8b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66
+    3f3100f026a9b5c53df1ef563f2e2b96;
+  f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b
+    ""
+    a9fdd55b4c5ff6687cd49667d60d525e;
+  6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    b9
+    09210b235e15e9984f6d728f4d266cc3;
+  aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa92
+    1ea465d576f919265add525cc88c6cca;
+  1451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e61766
+    9c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb6
+    b4e1b487ca7856e1a27ae343a761962f;
+}
+
+mars-ocb3 {
+  60d7bcda163547d348b75511
+    95e77022907dd1dff7dac5c9941d
+    ""
+    ""
+    ""
+    7c296d4449e64315d2b9f9ba0c3ff7d1;
+  26d0c6eb14ad568f86edd1dc
+    9268eeee533285a6ed810c9b689d
+    aa
+    ""
+    ""
+    b430fac783a66cc2daed259760916412;
+  a9060d2d4b6003062365b0a5
+    4364c76c160f11896c4794846ecf
+    ""
+    a1
+    67
+    06f7540f39167c5adfddad27cf702a2c;
+  4a7130c9f137120634c95198
+    48a877ff77bf79192a5b50
+    ""
+    ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160
+    871488d35db8121121e6c850c22cf29166fe1e351ce6f6027053f625dae6bded20dff82b546f8ba0806af4a9df2e3cd3
+    1cd5f303f4b515ea7c331533b41f4ac7;
+  ad10997a21635c6d62c92690
+    29df3e6057acc87638f5080467
+    33d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6
+    04aecdbb5ea1f384759cb21f922d4a5e5f41759933e7e12a46761a0bb58e8b13100338f8ac4f5d71a564d51d2e7ecefc
+    0fdac739fa9705100fb282f9c9c99668;
+  c95a97a48030370c33d090c5
+    4215abd6b3ad54efc9a38378c5b9
+    ""
+    3bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710
+    ecec35b67e05827d1c60b59197ddec40a4afc502e7b22194c710f2d5bb806fca221d81abdce4c507e02f65b5cca4e43f86f5f76f5f
+    4eba3f34ab847bcb7fc65d5b06406cec;
+  ee72807a2219bfb474fd71d8
+    91f24bb65d1563259f9eb53b571e
+    a629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cd
+    ec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f
+    ff28ac43e2c855d679ee89f7f8d4107c8a1c7c20a4f03b59544adaedd185a4e3a5a37ca45dc55e11df1cdaa7a374850225bffc3c26
+    2da2a1575b5dc344c32a8b2a0b4c3dd8;
+  5fe8368131115c037ba323fe1dc8151784873f0e
+    b5b647da6794c18b5337685a96ed
+    ""
+    ""
+    ""
+    f940a9debe160996da1f147aafcc566a;
+  65b9aca338527ef19b09c063c46f88de9fd41e72
+    d7b97e23e6eabdff3bcd21149926
+    88
+    ""
+    ""
+    92001d0836b97d87051c1f7d9d09f202;
+  78dbf30f1dad89d4b9b12012e4713df46795630e
+    7952d22bb02d7100b8b649377d20
+    ""
+    a8
+    74
+    67e9a575f013c2692d295c6103d0d0cf;
+  f083455b663e4ee1315f3c8f2aebfa921451dcd1
+    af5813b70d30ce2f1fef6e
+    ""
+    f315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cd
+    0a797f00e405100dadb704f4ff09a0a4a8cbe6cd46a0b27529f64b9c56f9d70e688fbe551fa24eb5d3609185b4bdceed
+    b672df8063219f6c88308bdd3a3ad799;
+  f0c8e30308be3c31e6bc58c0b7cadcb658b970e4
+    7479a684b5aefa69a4cd52147e
+    d12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4
+    ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc3990844
+    badad19dc5594c261a3c5f532b3dcfadfbb81fc53ed47dc2ed8327af497dd998714d1a882310f27ff3cb2c59c024d6e6
+    e4b3b99d7d2e296fb0c0de581f1b5fe9;
+  5608fe95e81c2533e31c9c1a9851bc2810d858cb
+    bc8424d126b807e6daa089c3f909
+    ""
+    9c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b73037
+    21a942eb29d65d2fbf4807ccbb084336916f1003941785547a5346c7eab40931819df2d8caa2549e942e1d09b84b260c7a0dfc0a10
+    672ef4305dcce1cfe09539670b14a261;
+  4ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    945ffd505003cc0cae9ce021a5f1
+    fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4
+    c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8de
+    2d0975faff0cd18b98e72bd93765dd3abd35cc4e3cfeb0b6cac1e15e9ed12b4aa038f51cc89b3576ff38a268be71215c4b01dcd552
+    b5237448fba31d61ebda5eeac052d5d6;
+  b9bd205b70e04c09
+    1d205cdad9e9a79b1abf91b0851e
+    ""
+    ""
+    ""
+    20c493b7bdf626905c987fb7bf10d8f7;
+  5ca605ac84513995
+    87011677508a15dde524af3e2bee
+    06
+    ""
+    ""
+    fa2df8b2eaad48b6bdf3c9bad2938049;
+  46541a42c2ecccb4
+    4d65bad397abfaf529ee41cf9a05
+    ""
+    c7
+    75
+    435dd63a2ce8c8458535cd09b20f8d3a;
+  efedef3401539c51
+    d2a90bbf7f1bfc338ab0ef
+    ""
+    5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068
+    64e098d90cbf96bc76262ab532cc962b17fa5c87938daba74d1af81bac2132abb0ff7c47ce79b02b4d6c863ef802d79b
+    f9732cb1c9f81e4e2a18bc027bb54a19;
+  a9f891bc5ba5afab
+    f8c3122d12d7ff3c41122d70d1
+    7d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad
+    68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8a
+    bd7f51b29f6c6f31d1be0eb43533bf93f1b32117242de5011d5e8b25fbb5692531fd3a6c9b48fad09bc80a142ff50ee1
+    86ebc023b905ca6caa36f50a8e18843d;
+  b9aea3ccf860b000
+    9740763d96836c5f87b95460938d
+    ""
+    e1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d964556
+    fe4fa4d02555e61c0bd04dff129a4d6936fb1f73d65dd7cd97bb33cb2367ad3cd6e837306ce8bb8f7ae139034d288069d9b25e8c60
+    ca2f4b45a793978f9bf62457f035ac75;
+  3a308ba600768175
+    23bd2abf1261b089d8f23a9c2835
+    076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e23
+    52fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799d
+    b15d10be578b00205857262c9108b92645914a0824925535feb7486fb53037fb93d5ff7d77acede5ddf9ece2422636baa4817f4ebb
+    adff289af064bd7145e742df30acc5fd;
+  c875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9
+    f81d14517ffae475f6b94a43a67b
+    ""
+    ""
+    ""
+    0742d3aab5b5f4338953a42eff9de1e4;
+  3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac197606
+    3e113ab61f813e28a1397a7974a1
+    d7
+    ""
+    ""
+    9960763f7362f798c6ca3adf09317bd1;
+  f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c89
+    3959b74dc23a7bb40e7e0013e515
+    ""
+    06
+    2d
+    1896462db7d41cf1dfc0e73f56e35e49;
+  86d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab
+    6cf8556b7aa776945948d1
+    ""
+    b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e
+    6a517fb1eddc5a9ffcf4b4dcae0c9d2e2f8f70b843e480d9b86d71fdbeebacd5a135f08de14ed70906ccbc4f6107b425
+    e699532063bc347b5273ab6c9aa5f8a7;
+  737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad
+    5b04140d98edabe08485290a4d
+    87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359
+    f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bac
+    8908a7b2b68ebc9659feb4a31163481275f0db4182b7051a9a50e9697f8115ff79368964e9661b2e2db5d2a4c86b5a23
+    33756a80721be9f1105c7afd703e21a0;
+  f6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d
+    73d192ee53b3f3ebd66ddd98cedb
+    ""
+    e88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb43392
+    cdcec7225d6eb19a12720cc24c2a672559618debfdf0ee0d0b350e2701a69124f28d1b76b322cecdadbc67e99342c59dabd11fbf23
+    fb30f854d45a706e84616a756a52e711;
+  2a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b5
+    4fd9d70c70e117bf1cae71b3a56f
+    0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597
+    a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe0
+    98463b6aa0363435ef5f9a71e67406202f51153781195a36bf467b301bf4a676c5af0b7011e15f1ecff79112847529137666ffe910
+    684543c8dbf9b01aee18f5eba0153a24;
+}
+
+mars-ocb3-mct {
+  56 3ba8a3d94c3f67e9cef8cf2142b367f7;
+  52 f743099826d0e38c48faf27d3edd5b22;
+  48 4345a17ed61d2a7b9289f0e12e4350f5;
+  44 ef3ad940f5e754a02317f3f1c489028c;
+  40 c618d5f97d8913f90a91caed561346c7;
+  36 96249ddf7bd91b1df2e2aed3c09bd194;
+  32 1f789304aff2376bf2feba8aa9191a05;
+  28 7a339727e025fcf65c08152217b95583;
+  24 d4d38f1f399005a03a185887fbcc6737;
+  20 45e7020dbfdd5f6d31cb441096faf69c;
+  16 6b5c2f90abb45cda3622baa74d486f02;
+  56 15a0597529ff0ec495e2abc1;
+  52 fbd7bfc60b66a65582e96109;
+  48 ae651ff80d12c1940539ae3e;
+  44 35db8939f38ed596f9940968;
+  40 fc4127740b0b0b7c07d2cf62;
+  36 282eec1a27cf55e9cda791b1;
+  32 95f745dd397a29d2dbcca030;
+  28 6935deaa6bc7da04dc7ab3e9;
+  24 f46ff7af02ea94fa45404e09;
+  20 2f41619c9f36bc9ed459d3b9;
+  16 c02f5b63d1ccbe71e928b16f;
+  56 05f4e466ef576d08;
+  52 b260ce024131b9ba;
+  48 ad7f2b73670c5238;
+  44 00a12cf14f6300bb;
+  40 f0bfc04f2ea1275a;
+  36 48585bf1735225ea;
+  32 838abfef38920bee;
+  28 fe4f81e7b258e614;
+  24 b1791137318f5946;
+  20 d67d45622c856251;
+  16 f34b97c87f3e6823;
+}
diff --git a/symm/t/modes/blowfish-cbc.regress b/symm/t/modes/blowfish-cbc.regress
new file mode 100644 (file)
index 0000000..85c0c05
Binary files /dev/null and b/symm/t/modes/blowfish-cbc.regress differ
diff --git a/symm/t/modes/blowfish-cfb.regress b/symm/t/modes/blowfish-cfb.regress
new file mode 100644 (file)
index 0000000..204cba0
Binary files /dev/null and b/symm/t/modes/blowfish-cfb.regress differ
diff --git a/symm/t/modes/blowfish-counter.regress b/symm/t/modes/blowfish-counter.regress
new file mode 100644 (file)
index 0000000..41591ee
Binary files /dev/null and b/symm/t/modes/blowfish-counter.regress differ
diff --git a/symm/t/modes/blowfish-ecb.regress b/symm/t/modes/blowfish-ecb.regress
new file mode 100644 (file)
index 0000000..293b77d
Binary files /dev/null and b/symm/t/modes/blowfish-ecb.regress differ
diff --git a/symm/t/modes/blowfish-ofb.regress b/symm/t/modes/blowfish-ofb.regress
new file mode 100644 (file)
index 0000000..1b37899
Binary files /dev/null and b/symm/t/modes/blowfish-ofb.regress differ
diff --git a/symm/t/modes/cast128-cbc.regress b/symm/t/modes/cast128-cbc.regress
new file mode 100644 (file)
index 0000000..f0942ad
Binary files /dev/null and b/symm/t/modes/cast128-cbc.regress differ
diff --git a/symm/t/modes/cast128-cfb.regress b/symm/t/modes/cast128-cfb.regress
new file mode 100644 (file)
index 0000000..1c859eb
Binary files /dev/null and b/symm/t/modes/cast128-cfb.regress differ
diff --git a/symm/t/modes/cast128-counter.regress b/symm/t/modes/cast128-counter.regress
new file mode 100644 (file)
index 0000000..25cc116
Binary files /dev/null and b/symm/t/modes/cast128-counter.regress differ
diff --git a/symm/t/modes/cast128-ecb.regress b/symm/t/modes/cast128-ecb.regress
new file mode 100644 (file)
index 0000000..30dda77
Binary files /dev/null and b/symm/t/modes/cast128-ecb.regress differ
diff --git a/symm/t/modes/cast128-ofb.regress b/symm/t/modes/cast128-ofb.regress
new file mode 100644 (file)
index 0000000..c1b5ab8
Binary files /dev/null and b/symm/t/modes/cast128-ofb.regress differ
diff --git a/symm/t/modes/cast256-cbc.regress b/symm/t/modes/cast256-cbc.regress
new file mode 100644 (file)
index 0000000..c81b343
Binary files /dev/null and b/symm/t/modes/cast256-cbc.regress differ
diff --git a/symm/t/modes/cast256-cfb.regress b/symm/t/modes/cast256-cfb.regress
new file mode 100644 (file)
index 0000000..15cace7
Binary files /dev/null and b/symm/t/modes/cast256-cfb.regress differ
diff --git a/symm/t/modes/cast256-counter.regress b/symm/t/modes/cast256-counter.regress
new file mode 100644 (file)
index 0000000..d3e4947
Binary files /dev/null and b/symm/t/modes/cast256-counter.regress differ
diff --git a/symm/t/modes/cast256-ecb.regress b/symm/t/modes/cast256-ecb.regress
new file mode 100644 (file)
index 0000000..b80c11b
Binary files /dev/null and b/symm/t/modes/cast256-ecb.regress differ
diff --git a/symm/t/modes/cast256-ofb.regress b/symm/t/modes/cast256-ofb.regress
new file mode 100644 (file)
index 0000000..947bee3
Binary files /dev/null and b/symm/t/modes/cast256-ofb.regress differ
diff --git a/symm/t/modes/des-cbc.regress b/symm/t/modes/des-cbc.regress
new file mode 100644 (file)
index 0000000..c423fb2
Binary files /dev/null and b/symm/t/modes/des-cbc.regress differ
diff --git a/symm/t/modes/des-cfb.regress b/symm/t/modes/des-cfb.regress
new file mode 100644 (file)
index 0000000..918db62
Binary files /dev/null and b/symm/t/modes/des-cfb.regress differ
diff --git a/symm/t/modes/des-counter.regress b/symm/t/modes/des-counter.regress
new file mode 100644 (file)
index 0000000..47eefc1
Binary files /dev/null and b/symm/t/modes/des-counter.regress differ
diff --git a/symm/t/modes/des-ecb.regress b/symm/t/modes/des-ecb.regress
new file mode 100644 (file)
index 0000000..412681e
Binary files /dev/null and b/symm/t/modes/des-ecb.regress differ
diff --git a/symm/t/modes/des-ofb.regress b/symm/t/modes/des-ofb.regress
new file mode 100644 (file)
index 0000000..72ae042
Binary files /dev/null and b/symm/t/modes/des-ofb.regress differ
diff --git a/symm/t/modes/des3-cbc.regress b/symm/t/modes/des3-cbc.regress
new file mode 100644 (file)
index 0000000..012065a
Binary files /dev/null and b/symm/t/modes/des3-cbc.regress differ
diff --git a/symm/t/modes/des3-cfb.regress b/symm/t/modes/des3-cfb.regress
new file mode 100644 (file)
index 0000000..c225f47
Binary files /dev/null and b/symm/t/modes/des3-cfb.regress differ
diff --git a/symm/t/modes/des3-counter.regress b/symm/t/modes/des3-counter.regress
new file mode 100644 (file)
index 0000000..05a7e4d
Binary files /dev/null and b/symm/t/modes/des3-counter.regress differ
diff --git a/symm/t/modes/des3-ecb.regress b/symm/t/modes/des3-ecb.regress
new file mode 100644 (file)
index 0000000..47b26ce
Binary files /dev/null and b/symm/t/modes/des3-ecb.regress differ
diff --git a/symm/t/modes/des3-ofb.regress b/symm/t/modes/des3-ofb.regress
new file mode 100644 (file)
index 0000000..febfc6c
Binary files /dev/null and b/symm/t/modes/des3-ofb.regress differ
diff --git a/symm/t/modes/desx-cbc.regress b/symm/t/modes/desx-cbc.regress
new file mode 100644 (file)
index 0000000..253251d
Binary files /dev/null and b/symm/t/modes/desx-cbc.regress differ
diff --git a/symm/t/modes/desx-cfb.regress b/symm/t/modes/desx-cfb.regress
new file mode 100644 (file)
index 0000000..83d2aa0
Binary files /dev/null and b/symm/t/modes/desx-cfb.regress differ
diff --git a/symm/t/modes/desx-counter.regress b/symm/t/modes/desx-counter.regress
new file mode 100644 (file)
index 0000000..a017464
Binary files /dev/null and b/symm/t/modes/desx-counter.regress differ
diff --git a/symm/t/modes/desx-ecb.regress b/symm/t/modes/desx-ecb.regress
new file mode 100644 (file)
index 0000000..bd32a6e
Binary files /dev/null and b/symm/t/modes/desx-ecb.regress differ
diff --git a/symm/t/modes/desx-ofb.regress b/symm/t/modes/desx-ofb.regress
new file mode 100644 (file)
index 0000000..f6e1a8b
Binary files /dev/null and b/symm/t/modes/desx-ofb.regress differ
diff --git a/symm/t/modes/has160-mgf.regress b/symm/t/modes/has160-mgf.regress
new file mode 100644 (file)
index 0000000..516a475
Binary files /dev/null and b/symm/t/modes/has160-mgf.regress differ
diff --git a/symm/t/modes/idea-cbc.regress b/symm/t/modes/idea-cbc.regress
new file mode 100644 (file)
index 0000000..57230ed
Binary files /dev/null and b/symm/t/modes/idea-cbc.regress differ
diff --git a/symm/t/modes/idea-cfb.regress b/symm/t/modes/idea-cfb.regress
new file mode 100644 (file)
index 0000000..76f0995
Binary files /dev/null and b/symm/t/modes/idea-cfb.regress differ
diff --git a/symm/t/modes/idea-counter.regress b/symm/t/modes/idea-counter.regress
new file mode 100644 (file)
index 0000000..d825c4d
Binary files /dev/null and b/symm/t/modes/idea-counter.regress differ
diff --git a/symm/t/modes/idea-ecb.regress b/symm/t/modes/idea-ecb.regress
new file mode 100644 (file)
index 0000000..e573d52
Binary files /dev/null and b/symm/t/modes/idea-ecb.regress differ
diff --git a/symm/t/modes/idea-ofb.regress b/symm/t/modes/idea-ofb.regress
new file mode 100644 (file)
index 0000000..01fd5dc
Binary files /dev/null and b/symm/t/modes/idea-ofb.regress differ
diff --git a/symm/t/modes/mars-cbc.regress b/symm/t/modes/mars-cbc.regress
new file mode 100644 (file)
index 0000000..30d4d7e
Binary files /dev/null and b/symm/t/modes/mars-cbc.regress differ
diff --git a/symm/t/modes/mars-cfb.regress b/symm/t/modes/mars-cfb.regress
new file mode 100644 (file)
index 0000000..0874aaa
Binary files /dev/null and b/symm/t/modes/mars-cfb.regress differ
diff --git a/symm/t/modes/mars-counter.regress b/symm/t/modes/mars-counter.regress
new file mode 100644 (file)
index 0000000..145e943
Binary files /dev/null and b/symm/t/modes/mars-counter.regress differ
diff --git a/symm/t/modes/mars-ecb.regress b/symm/t/modes/mars-ecb.regress
new file mode 100644 (file)
index 0000000..d7f96df
Binary files /dev/null and b/symm/t/modes/mars-ecb.regress differ
diff --git a/symm/t/modes/mars-ofb.regress b/symm/t/modes/mars-ofb.regress
new file mode 100644 (file)
index 0000000..c29b704
Binary files /dev/null and b/symm/t/modes/mars-ofb.regress differ
diff --git a/symm/t/modes/md2-mgf.regress b/symm/t/modes/md2-mgf.regress
new file mode 100644 (file)
index 0000000..652a65e
Binary files /dev/null and b/symm/t/modes/md2-mgf.regress differ
diff --git a/symm/t/modes/md4-mgf.regress b/symm/t/modes/md4-mgf.regress
new file mode 100644 (file)
index 0000000..e138a74
Binary files /dev/null and b/symm/t/modes/md4-mgf.regress differ
diff --git a/symm/t/modes/md5-mgf.regress b/symm/t/modes/md5-mgf.regress
new file mode 100644 (file)
index 0000000..96bd16a
Binary files /dev/null and b/symm/t/modes/md5-mgf.regress differ
diff --git a/symm/t/modes/noekeon-cbc.regress b/symm/t/modes/noekeon-cbc.regress
new file mode 100644 (file)
index 0000000..5b3e218
Binary files /dev/null and b/symm/t/modes/noekeon-cbc.regress differ
diff --git a/symm/t/modes/noekeon-cfb.regress b/symm/t/modes/noekeon-cfb.regress
new file mode 100644 (file)
index 0000000..75ce901
Binary files /dev/null and b/symm/t/modes/noekeon-cfb.regress differ
diff --git a/symm/t/modes/noekeon-counter.regress b/symm/t/modes/noekeon-counter.regress
new file mode 100644 (file)
index 0000000..464ff7f
Binary files /dev/null and b/symm/t/modes/noekeon-counter.regress differ
diff --git a/symm/t/modes/noekeon-ecb.regress b/symm/t/modes/noekeon-ecb.regress
new file mode 100644 (file)
index 0000000..9a8efe4
Binary files /dev/null and b/symm/t/modes/noekeon-ecb.regress differ
diff --git a/symm/t/modes/noekeon-ofb.regress b/symm/t/modes/noekeon-ofb.regress
new file mode 100644 (file)
index 0000000..91cedd8
Binary files /dev/null and b/symm/t/modes/noekeon-ofb.regress differ
diff --git a/symm/t/modes/rc2-cbc.regress b/symm/t/modes/rc2-cbc.regress
new file mode 100644 (file)
index 0000000..8d49c5a
Binary files /dev/null and b/symm/t/modes/rc2-cbc.regress differ
diff --git a/symm/t/modes/rc2-cfb.regress b/symm/t/modes/rc2-cfb.regress
new file mode 100644 (file)
index 0000000..71ca172
Binary files /dev/null and b/symm/t/modes/rc2-cfb.regress differ
diff --git a/symm/t/modes/rc2-counter.regress b/symm/t/modes/rc2-counter.regress
new file mode 100644 (file)
index 0000000..f57e031
Binary files /dev/null and b/symm/t/modes/rc2-counter.regress differ
diff --git a/symm/t/modes/rc2-ecb.regress b/symm/t/modes/rc2-ecb.regress
new file mode 100644 (file)
index 0000000..07910a7
Binary files /dev/null and b/symm/t/modes/rc2-ecb.regress differ
diff --git a/symm/t/modes/rc2-ofb.regress b/symm/t/modes/rc2-ofb.regress
new file mode 100644 (file)
index 0000000..39c837f
Binary files /dev/null and b/symm/t/modes/rc2-ofb.regress differ
diff --git a/symm/t/modes/rc5-cbc.regress b/symm/t/modes/rc5-cbc.regress
new file mode 100644 (file)
index 0000000..0689ba4
Binary files /dev/null and b/symm/t/modes/rc5-cbc.regress differ
diff --git a/symm/t/modes/rc5-cfb.regress b/symm/t/modes/rc5-cfb.regress
new file mode 100644 (file)
index 0000000..5cd4011
Binary files /dev/null and b/symm/t/modes/rc5-cfb.regress differ
diff --git a/symm/t/modes/rc5-counter.regress b/symm/t/modes/rc5-counter.regress
new file mode 100644 (file)
index 0000000..5700843
Binary files /dev/null and b/symm/t/modes/rc5-counter.regress differ
diff --git a/symm/t/modes/rc5-ecb.regress b/symm/t/modes/rc5-ecb.regress
new file mode 100644 (file)
index 0000000..0ed3ee6
Binary files /dev/null and b/symm/t/modes/rc5-ecb.regress differ
diff --git a/symm/t/modes/rc5-ofb.regress b/symm/t/modes/rc5-ofb.regress
new file mode 100644 (file)
index 0000000..28103d7
Binary files /dev/null and b/symm/t/modes/rc5-ofb.regress differ
diff --git a/symm/t/modes/rijndael-cbc.regress b/symm/t/modes/rijndael-cbc.regress
new file mode 100644 (file)
index 0000000..2d44c16
Binary files /dev/null and b/symm/t/modes/rijndael-cbc.regress differ
diff --git a/symm/t/modes/rijndael-cfb.regress b/symm/t/modes/rijndael-cfb.regress
new file mode 100644 (file)
index 0000000..d0cb101
Binary files /dev/null and b/symm/t/modes/rijndael-cfb.regress differ
diff --git a/symm/t/modes/rijndael-counter.regress b/symm/t/modes/rijndael-counter.regress
new file mode 100644 (file)
index 0000000..49ae7af
Binary files /dev/null and b/symm/t/modes/rijndael-counter.regress differ
diff --git a/symm/t/modes/rijndael-ecb.regress b/symm/t/modes/rijndael-ecb.regress
new file mode 100644 (file)
index 0000000..2668a62
Binary files /dev/null and b/symm/t/modes/rijndael-ecb.regress differ
diff --git a/symm/t/modes/rijndael-ofb.regress b/symm/t/modes/rijndael-ofb.regress
new file mode 100644 (file)
index 0000000..6bc7d19
Binary files /dev/null and b/symm/t/modes/rijndael-ofb.regress differ
diff --git a/symm/t/modes/rijndael192-cbc.regress b/symm/t/modes/rijndael192-cbc.regress
new file mode 100644 (file)
index 0000000..99673d9
Binary files /dev/null and b/symm/t/modes/rijndael192-cbc.regress differ
diff --git a/symm/t/modes/rijndael192-cfb.regress b/symm/t/modes/rijndael192-cfb.regress
new file mode 100644 (file)
index 0000000..899550e
Binary files /dev/null and b/symm/t/modes/rijndael192-cfb.regress differ
diff --git a/symm/t/modes/rijndael192-counter.regress b/symm/t/modes/rijndael192-counter.regress
new file mode 100644 (file)
index 0000000..5b89d87
Binary files /dev/null and b/symm/t/modes/rijndael192-counter.regress differ
diff --git a/symm/t/modes/rijndael192-ecb.regress b/symm/t/modes/rijndael192-ecb.regress
new file mode 100644 (file)
index 0000000..3420f8a
Binary files /dev/null and b/symm/t/modes/rijndael192-ecb.regress differ
diff --git a/symm/t/modes/rijndael192-ofb.regress b/symm/t/modes/rijndael192-ofb.regress
new file mode 100644 (file)
index 0000000..6885dc2
Binary files /dev/null and b/symm/t/modes/rijndael192-ofb.regress differ
diff --git a/symm/t/modes/rijndael256-cbc.regress b/symm/t/modes/rijndael256-cbc.regress
new file mode 100644 (file)
index 0000000..d1f4f96
Binary files /dev/null and b/symm/t/modes/rijndael256-cbc.regress differ
diff --git a/symm/t/modes/rijndael256-cfb.regress b/symm/t/modes/rijndael256-cfb.regress
new file mode 100644 (file)
index 0000000..4e21cd6
Binary files /dev/null and b/symm/t/modes/rijndael256-cfb.regress differ
diff --git a/symm/t/modes/rijndael256-counter.regress b/symm/t/modes/rijndael256-counter.regress
new file mode 100644 (file)
index 0000000..a0eb2f3
Binary files /dev/null and b/symm/t/modes/rijndael256-counter.regress differ
diff --git a/symm/t/modes/rijndael256-ecb.regress b/symm/t/modes/rijndael256-ecb.regress
new file mode 100644 (file)
index 0000000..c82a4b2
Binary files /dev/null and b/symm/t/modes/rijndael256-ecb.regress differ
diff --git a/symm/t/modes/rijndael256-ofb.regress b/symm/t/modes/rijndael256-ofb.regress
new file mode 100644 (file)
index 0000000..45c4091
Binary files /dev/null and b/symm/t/modes/rijndael256-ofb.regress differ
diff --git a/symm/t/modes/rmd128-mgf.regress b/symm/t/modes/rmd128-mgf.regress
new file mode 100644 (file)
index 0000000..27b3f4c
Binary files /dev/null and b/symm/t/modes/rmd128-mgf.regress differ
diff --git a/symm/t/modes/rmd160-mgf.regress b/symm/t/modes/rmd160-mgf.regress
new file mode 100644 (file)
index 0000000..53d466f
Binary files /dev/null and b/symm/t/modes/rmd160-mgf.regress differ
diff --git a/symm/t/modes/rmd256-mgf.regress b/symm/t/modes/rmd256-mgf.regress
new file mode 100644 (file)
index 0000000..4a15390
Binary files /dev/null and b/symm/t/modes/rmd256-mgf.regress differ
diff --git a/symm/t/modes/rmd320-mgf.regress b/symm/t/modes/rmd320-mgf.regress
new file mode 100644 (file)
index 0000000..82b10f3
Binary files /dev/null and b/symm/t/modes/rmd320-mgf.regress differ
diff --git a/symm/t/modes/safer-cbc.regress b/symm/t/modes/safer-cbc.regress
new file mode 100644 (file)
index 0000000..a23aa49
Binary files /dev/null and b/symm/t/modes/safer-cbc.regress differ
diff --git a/symm/t/modes/safer-cfb.regress b/symm/t/modes/safer-cfb.regress
new file mode 100644 (file)
index 0000000..0c49a5c
Binary files /dev/null and b/symm/t/modes/safer-cfb.regress differ
diff --git a/symm/t/modes/safer-counter.regress b/symm/t/modes/safer-counter.regress
new file mode 100644 (file)
index 0000000..03ff097
Binary files /dev/null and b/symm/t/modes/safer-counter.regress differ
diff --git a/symm/t/modes/safer-ecb.regress b/symm/t/modes/safer-ecb.regress
new file mode 100644 (file)
index 0000000..882ff98
Binary files /dev/null and b/symm/t/modes/safer-ecb.regress differ
diff --git a/symm/t/modes/safer-ofb.regress b/symm/t/modes/safer-ofb.regress
new file mode 100644 (file)
index 0000000..b06625b
Binary files /dev/null and b/symm/t/modes/safer-ofb.regress differ
diff --git a/symm/t/modes/safersk-cbc.regress b/symm/t/modes/safersk-cbc.regress
new file mode 100644 (file)
index 0000000..9816c41
Binary files /dev/null and b/symm/t/modes/safersk-cbc.regress differ
diff --git a/symm/t/modes/safersk-cfb.regress b/symm/t/modes/safersk-cfb.regress
new file mode 100644 (file)
index 0000000..8db489f
Binary files /dev/null and b/symm/t/modes/safersk-cfb.regress differ
diff --git a/symm/t/modes/safersk-counter.regress b/symm/t/modes/safersk-counter.regress
new file mode 100644 (file)
index 0000000..a40cd29
Binary files /dev/null and b/symm/t/modes/safersk-counter.regress differ
diff --git a/symm/t/modes/safersk-ecb.regress b/symm/t/modes/safersk-ecb.regress
new file mode 100644 (file)
index 0000000..fcba346
Binary files /dev/null and b/symm/t/modes/safersk-ecb.regress differ
diff --git a/symm/t/modes/safersk-ofb.regress b/symm/t/modes/safersk-ofb.regress
new file mode 100644 (file)
index 0000000..36288cc
Binary files /dev/null and b/symm/t/modes/safersk-ofb.regress differ
diff --git a/symm/t/modes/serpent-cbc.regress b/symm/t/modes/serpent-cbc.regress
new file mode 100644 (file)
index 0000000..0f879de
Binary files /dev/null and b/symm/t/modes/serpent-cbc.regress differ
diff --git a/symm/t/modes/serpent-cfb.regress b/symm/t/modes/serpent-cfb.regress
new file mode 100644 (file)
index 0000000..0d27530
Binary files /dev/null and b/symm/t/modes/serpent-cfb.regress differ
diff --git a/symm/t/modes/serpent-counter.regress b/symm/t/modes/serpent-counter.regress
new file mode 100644 (file)
index 0000000..855d60a
Binary files /dev/null and b/symm/t/modes/serpent-counter.regress differ
diff --git a/symm/t/modes/serpent-ecb.regress b/symm/t/modes/serpent-ecb.regress
new file mode 100644 (file)
index 0000000..5306e95
Binary files /dev/null and b/symm/t/modes/serpent-ecb.regress differ
diff --git a/symm/t/modes/serpent-ofb.regress b/symm/t/modes/serpent-ofb.regress
new file mode 100644 (file)
index 0000000..3b5e6e7
Binary files /dev/null and b/symm/t/modes/serpent-ofb.regress differ
diff --git a/symm/t/modes/sha-mgf.regress b/symm/t/modes/sha-mgf.regress
new file mode 100644 (file)
index 0000000..797011a
Binary files /dev/null and b/symm/t/modes/sha-mgf.regress differ
diff --git a/symm/t/modes/sha224-mgf.regress b/symm/t/modes/sha224-mgf.regress
new file mode 100644 (file)
index 0000000..559e830
Binary files /dev/null and b/symm/t/modes/sha224-mgf.regress differ
diff --git a/symm/t/modes/sha256-mgf.regress b/symm/t/modes/sha256-mgf.regress
new file mode 100644 (file)
index 0000000..b6aa141
Binary files /dev/null and b/symm/t/modes/sha256-mgf.regress differ
diff --git a/symm/t/modes/sha3-224-mgf.regress b/symm/t/modes/sha3-224-mgf.regress
new file mode 100644 (file)
index 0000000..5bd9f01
Binary files /dev/null and b/symm/t/modes/sha3-224-mgf.regress differ
diff --git a/symm/t/modes/sha3-256-mgf.regress b/symm/t/modes/sha3-256-mgf.regress
new file mode 100644 (file)
index 0000000..0324143
Binary files /dev/null and b/symm/t/modes/sha3-256-mgf.regress differ
diff --git a/symm/t/modes/sha3-384-mgf.regress b/symm/t/modes/sha3-384-mgf.regress
new file mode 100644 (file)
index 0000000..dc86c05
Binary files /dev/null and b/symm/t/modes/sha3-384-mgf.regress differ
diff --git a/symm/t/modes/sha3-512-mgf.regress b/symm/t/modes/sha3-512-mgf.regress
new file mode 100644 (file)
index 0000000..e9b0fe0
Binary files /dev/null and b/symm/t/modes/sha3-512-mgf.regress differ
diff --git a/symm/t/modes/sha384-mgf.regress b/symm/t/modes/sha384-mgf.regress
new file mode 100644 (file)
index 0000000..bf688b2
Binary files /dev/null and b/symm/t/modes/sha384-mgf.regress differ
diff --git a/symm/t/modes/sha512-224-mgf.regress b/symm/t/modes/sha512-224-mgf.regress
new file mode 100644 (file)
index 0000000..ccd94ba
Binary files /dev/null and b/symm/t/modes/sha512-224-mgf.regress differ
diff --git a/symm/t/modes/sha512-256-mgf.regress b/symm/t/modes/sha512-256-mgf.regress
new file mode 100644 (file)
index 0000000..a01aa7a
Binary files /dev/null and b/symm/t/modes/sha512-256-mgf.regress differ
diff --git a/symm/t/modes/sha512-mgf.regress b/symm/t/modes/sha512-mgf.regress
new file mode 100644 (file)
index 0000000..3dae6fa
Binary files /dev/null and b/symm/t/modes/sha512-mgf.regress differ
diff --git a/symm/t/modes/skipjack-cbc.regress b/symm/t/modes/skipjack-cbc.regress
new file mode 100644 (file)
index 0000000..a1fad97
Binary files /dev/null and b/symm/t/modes/skipjack-cbc.regress differ
diff --git a/symm/t/modes/skipjack-cfb.regress b/symm/t/modes/skipjack-cfb.regress
new file mode 100644 (file)
index 0000000..3186986
Binary files /dev/null and b/symm/t/modes/skipjack-cfb.regress differ
diff --git a/symm/t/modes/skipjack-counter.regress b/symm/t/modes/skipjack-counter.regress
new file mode 100644 (file)
index 0000000..33a0ab1
Binary files /dev/null and b/symm/t/modes/skipjack-counter.regress differ
diff --git a/symm/t/modes/skipjack-ecb.regress b/symm/t/modes/skipjack-ecb.regress
new file mode 100644 (file)
index 0000000..6cbf31c
Binary files /dev/null and b/symm/t/modes/skipjack-ecb.regress differ
diff --git a/symm/t/modes/skipjack-ofb.regress b/symm/t/modes/skipjack-ofb.regress
new file mode 100644 (file)
index 0000000..2ff46ea
Binary files /dev/null and b/symm/t/modes/skipjack-ofb.regress differ
diff --git a/symm/t/modes/square-cbc.regress b/symm/t/modes/square-cbc.regress
new file mode 100644 (file)
index 0000000..40008aa
Binary files /dev/null and b/symm/t/modes/square-cbc.regress differ
diff --git a/symm/t/modes/square-cfb.regress b/symm/t/modes/square-cfb.regress
new file mode 100644 (file)
index 0000000..b8dda4e
Binary files /dev/null and b/symm/t/modes/square-cfb.regress differ
diff --git a/symm/t/modes/square-counter.regress b/symm/t/modes/square-counter.regress
new file mode 100644 (file)
index 0000000..39be028
Binary files /dev/null and b/symm/t/modes/square-counter.regress differ
diff --git a/symm/t/modes/square-ecb.regress b/symm/t/modes/square-ecb.regress
new file mode 100644 (file)
index 0000000..8aeff53
Binary files /dev/null and b/symm/t/modes/square-ecb.regress differ
diff --git a/symm/t/modes/square-ofb.regress b/symm/t/modes/square-ofb.regress
new file mode 100644 (file)
index 0000000..f718ed3
Binary files /dev/null and b/symm/t/modes/square-ofb.regress differ
diff --git a/symm/t/modes/tea-cbc.regress b/symm/t/modes/tea-cbc.regress
new file mode 100644 (file)
index 0000000..103aa1d
Binary files /dev/null and b/symm/t/modes/tea-cbc.regress differ
diff --git a/symm/t/modes/tea-cfb.regress b/symm/t/modes/tea-cfb.regress
new file mode 100644 (file)
index 0000000..78d0c7b
Binary files /dev/null and b/symm/t/modes/tea-cfb.regress differ
diff --git a/symm/t/modes/tea-counter.regress b/symm/t/modes/tea-counter.regress
new file mode 100644 (file)
index 0000000..d637d2d
Binary files /dev/null and b/symm/t/modes/tea-counter.regress differ
diff --git a/symm/t/modes/tea-ecb.regress b/symm/t/modes/tea-ecb.regress
new file mode 100644 (file)
index 0000000..8524c0c
Binary files /dev/null and b/symm/t/modes/tea-ecb.regress differ
diff --git a/symm/t/modes/tea-ofb.regress b/symm/t/modes/tea-ofb.regress
new file mode 100644 (file)
index 0000000..679611b
Binary files /dev/null and b/symm/t/modes/tea-ofb.regress differ
diff --git a/symm/t/modes/tiger-mgf.regress b/symm/t/modes/tiger-mgf.regress
new file mode 100644 (file)
index 0000000..497a490
Binary files /dev/null and b/symm/t/modes/tiger-mgf.regress differ
diff --git a/symm/t/modes/twofish-cbc.regress b/symm/t/modes/twofish-cbc.regress
new file mode 100644 (file)
index 0000000..bf01929
Binary files /dev/null and b/symm/t/modes/twofish-cbc.regress differ
diff --git a/symm/t/modes/twofish-cfb.regress b/symm/t/modes/twofish-cfb.regress
new file mode 100644 (file)
index 0000000..c3f9ea2
Binary files /dev/null and b/symm/t/modes/twofish-cfb.regress differ
diff --git a/symm/t/modes/twofish-counter.regress b/symm/t/modes/twofish-counter.regress
new file mode 100644 (file)
index 0000000..ad27602
Binary files /dev/null and b/symm/t/modes/twofish-counter.regress differ
diff --git a/symm/t/modes/twofish-ecb.regress b/symm/t/modes/twofish-ecb.regress
new file mode 100644 (file)
index 0000000..58e4f93
Binary files /dev/null and b/symm/t/modes/twofish-ecb.regress differ
diff --git a/symm/t/modes/twofish-ofb.regress b/symm/t/modes/twofish-ofb.regress
new file mode 100644 (file)
index 0000000..a11550a
Binary files /dev/null and b/symm/t/modes/twofish-ofb.regress differ
diff --git a/symm/t/modes/whirlpool-mgf.regress b/symm/t/modes/whirlpool-mgf.regress
new file mode 100644 (file)
index 0000000..0f48f39
Binary files /dev/null and b/symm/t/modes/whirlpool-mgf.regress differ
diff --git a/symm/t/modes/whirlpool256-mgf.regress b/symm/t/modes/whirlpool256-mgf.regress
new file mode 100644 (file)
index 0000000..5051954
Binary files /dev/null and b/symm/t/modes/whirlpool256-mgf.regress differ
diff --git a/symm/t/modes/xtea-cbc.regress b/symm/t/modes/xtea-cbc.regress
new file mode 100644 (file)
index 0000000..04f4ea2
Binary files /dev/null and b/symm/t/modes/xtea-cbc.regress differ
diff --git a/symm/t/modes/xtea-cfb.regress b/symm/t/modes/xtea-cfb.regress
new file mode 100644 (file)
index 0000000..3bde823
Binary files /dev/null and b/symm/t/modes/xtea-cfb.regress differ
diff --git a/symm/t/modes/xtea-counter.regress b/symm/t/modes/xtea-counter.regress
new file mode 100644 (file)
index 0000000..f56c42a
Binary files /dev/null and b/symm/t/modes/xtea-counter.regress differ
diff --git a/symm/t/modes/xtea-ecb.regress b/symm/t/modes/xtea-ecb.regress
new file mode 100644 (file)
index 0000000..cc252a6
Binary files /dev/null and b/symm/t/modes/xtea-ecb.regress differ
diff --git a/symm/t/modes/xtea-ofb.regress b/symm/t/modes/xtea-ofb.regress
new file mode 100644 (file)
index 0000000..ef53aff
Binary files /dev/null and b/symm/t/modes/xtea-ofb.regress differ
index 0764732..0238228 100644 (file)
@@ -8,3 +8,246 @@ noekeon {
   ba6933819299c71699a99f08f678178b
     52f88a7b283c1f7bdf7b6faa5011c7d8 5096f2bfc82ae6e2d9495515c277fa70;
 }
+
+noekeon-cmac {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    2863ef2fdd68856576cdd771bfa6f2d5;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    f8e7683bb1eaa6647a054678315b5eda;
+  14ad568f86edd1dc9268eeee533285a6
+    ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a8
+    0a792a2d00ebcf99531795f4b5014e2e;
+  77ff77bf79192a5b50ade5d9cd739a3d
+    1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10
+    c123e79e5caf935e4534444d32d814d3;
+}
+
+noekeon-ccm {
+  e4bef260d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9
+    ""
+    ""
+    ""
+    49ba308e;
+  941d26d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b68
+    9d
+    ""
+    ""
+    bf7a3a76;
+  aaa9060d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecf
+    ""
+    a1
+    07
+    f4749361;
+  4a7130c9f137120634c9519848a877ff
+    77bf79192a5b50ade5
+    d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7
+    4c78845e20c686f9ff85982d36d3e9aa511ca2e24d03978efbcc2728d499114cfec92bac5f9913c6fab485e7dced9599
+    ed048b86e5dbb933f5893750dc0634cd;
+  b1cc49ae1d50c38201a894476b3f102b
+    752eb9529533966f27
+    043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac
+    0c825df862df85bf1bb99434c39ce83a392f0e03ca915677bfc6f7de8cf1643c70f679f8dc8d245fb2c84be5f05b5e6064ff017589
+    c9d921b8c460e2dab218d13a0609a344;
+}
+
+noekeon-eax {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    086d221cf45f48c8c1f0c176c227db42;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    ""
+    ""
+    ""
+    5599da97576ed0f456791a6d00e17288;
+  14ad568f86edd1dc9268eeee533285a6
+    ""
+    ed
+    ""
+    ""
+    40e6658bc9910a80906ad1337c633782;
+  810c9b689daaa9060d2d4b6003062365
+    ""
+    ""
+    b0
+    f2
+    205c5f8a0dbeefddbead7141069de5d7;
+  a54364c76c160f11896c4794846ecfa1
+    4a7130c9f137120634c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    3aae83e95da014773b3575f62054485064a2e2070a0449ab21a5dcdda2ff10d572e475a29d0bb4710a95c109641de055
+    8dc62b8af3aeb306e9469d238906612e;
+  05e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f102b752eb9529533
+    966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4
+    f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe
+    5fe35fcbf55279bdca2295b483181ccff932771ccd59aa3e35b39b6564032af118547a9704fffe57c789a88b70c7eca6eaabea82b8
+    4953808f5678ba307676326facca87d2;
+}
+
+noekeon-gcm {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    d739a8af18e930e49547f57c7454eb47;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    ""
+    ""
+    ""
+    6b26f591dfb442623c1590caefa4d323;
+  14ad568f86edd1dc9268eeee533285a6
+    ""
+    ed
+    ""
+    ""
+    77fc8f1632e4f4294f6b9df680afc350;
+  810c9b689daaa9060d2d4b6003062365
+    ""
+    ""
+    b0
+    26
+    e6aa7e364110e5c886e865b8fbffbece;
+  a54364c76c160f11896c4794846ecfa1
+    4a7130c9f137120634c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    7d5aef8b63a47da6a441fa4e9b36c31c39c58ac1d95728acf41ca1f81784cfb58b66ad385bc75e43062531cb3e5a5662
+    8dcf9c1d3abaf968a359afb853e866bc;
+  05e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f102b752eb9
+    529533966f27043eb621b7f65b000961040ef2
+    f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378
+    55ada77e6525df0ec6c424d43cedc25f04a9b1d37d2813c1ebc6a35d157c3137cb5f04753e86676a111d72e7303bb8430ac48f65fa5b125e7a
+    8c0d31d253b49759c1289ca15bdd068a;
+  c5b93bf4f2aad2605faee2b03fb648e2
+    7fff63102758fe2b69ac26afa33498
+    29b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563
+    259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f76
+    3e98ad97b1901fa089ddb06696ad688a3de2274b81d49c3198c17b2c1bd19556d0679d64d61f034880c89f111631bf78c4512599d7
+    5942a749a90e4af467a8a5782590dc69;
+}
+
+noekeon-ocb1 {
+  e4bef260d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26d0c6
+    ""
+    ""
+    ""
+    5081208cd2d5472d061211afba47e43a;
+  eb14ad568f86edd1dc9268eeee533285
+    a6ed810c9b689daaa9060d2d4b600306
+    23
+    ""
+    ""
+    e7162034dc92f809d9d9e7e41d9018bc;
+  65b0a54364c76c160f11896c4794846e
+    cfa14a7130c9f137120634c9519848a8
+    ""
+    77
+    59
+    fb7d568a9d2b0d8d33ca41930bd73d3f;
+  ff77bf79192a5b50ade5d9cd739a3d1f
+    337f29549e6b0d27a4ba234085406a61
+    ""
+    36512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f50804
+    86ec994914704bd64a4a2b519d43c2efd4554cd0e7cc41a91f25137ac94218e5622df9670340515ef947f90cfe6c0484
+    e72bacd856c8262a0d0bfc10ffb9fdd4;
+  6733d9ff61cdbda3b3e9878731ebfedd
+    4705e505da1435dceaa7b1cc49ae1d50
+    c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda1
+    9d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2
+    83eac3304197940d9942306411887d6809d9f04a4bdcea111a877f2579779bbb9dcc0738ea8e05cfd3aa48823ca8abd8
+    76d9c5343a98b1a9e90c8ce4978efd2b;
+  605faee2b03fb648e27fff63102758fe
+    2b69ac26afa3349829b94586306fed54
+    ""
+    154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800
+    18adeeddc2d0656141002e939240aa51080969442d958a78b499fb587f585c6688fed54c528603e75c756c490fa9f1486775a01514
+    1974d395a27da8b706de45c0821c6e68;
+  df9fcbaca48b77dba189196d1ebba10b
+    0467cb9fc2712a199e533fa9156308cd
+    ec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0b
+    ad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b
+    8c38ca85e4711e354e2662ff977da8ed51aca92d50c1fc40e21fde2e481f93e5c9fc454881eea55c8b6758ce6bf6adff18e01825af
+    cbe1c75a2354cf5dc1df8a6eb6ede687;
+}
+
+noekeon-pmac1 {
+  e4bef260d7bcda163547d348b7551195
+    ""
+    12679e29381d4258973a3d59f3405ec9;
+  e77022907dd1dff7dac5c9941d26d0c6
+    eb
+    a8cf4e78783c841939afff131c3b0b42;
+  14ad568f86edd1dc9268eeee533285a6
+    ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a8
+    1b01bbe2a8cbae52485e4d410f94ce1e;
+  77ff77bf79192a5b50ade5d9cd739a3d
+    1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10
+    35b9675a79680b83422e4282cc260583;
+}
+
+noekeon-ocb3 {
+  e4bef260d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26
+    ""
+    ""
+    ""
+    064d07192f9b79d8bc4611a94783465b;
+  d0c6eb14ad568f86edd1dc9268eeee53
+    3285a6ed810c9b689daaa9060d2d
+    4b
+    ""
+    ""
+    37ad7dbe61111839a2bbead7eec6358a;
+  6003062365b0a54364c76c160f11896c
+    4794846ecfa14a7130c9f1371206
+    ""
+    34
+    76
+    73f39959389362724e3785d929b00e8c;
+  c9519848a877ff77bf79192a5b50ade5
+    d9cd739a3d1f337f29549e
+    ""
+    6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029
+    820db0cbad206848e689523feda637ed12f58eaa9f133457937c505778b55369994f1c339ca3d2c044578450d5905c22
+    a0205c94e65a8712262a1d127f9d22da;
+  df3e6057acc87638f508046733d9ff61
+    cdbda3b3e9878731ebfedd4705
+    e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2
+    fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3
+    d79866f055cda0abb2ad06098f8c651ed32d5550d021bfd59fffd34433b04483d0d402fce3309a760720fadd094c8ee1
+    14c60ff87068d3d52be11c8472174f77;
+  ad54efc9a38378c5b93bf4f2aad2605f
+    aee2b03fb648e27fff63102758fe
+    ""
+    2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f
+    dcda3a90b5db824f1d54c569db8d543bb323ff0aa596a8779b7b94c3f397b193e3762cea731fe84ed5e7bd517641466550043faad9
+    b92101660872e1e7a951e8d8bab834c9;
+  9eb53b571ea629c54d57dd2d42f70800
+    df9fcbaca48b77dba189196d1ebb
+    a10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b
+    0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da67
+    42b20072cef90e896f11993737b645f8e42c172527cd4ddaa5ec2e54d4bb7f234062d707b63c87624b8e16273bce20e835f3374199
+    915583e7c80edec73b6d59c12a2a196f;
+}
+
+noekeon-ocb3-mct {
+  16 4d9b245d6fab392f1c5364a2ef5b96fb;
+  16 3b08aa07a8a40dc29e87a831;
+  16 9e400fc6449969f2;
+}
index ed90d3f..78c134a 100644 (file)
@@ -11,3 +11,912 @@ rc2 {
    88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e 129
    0000000000000000 5b78d3a43dfff1f1;
 }
+
+rc2-cmac {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268ee
+    ""
+    994f0987c07cbba3;
+  ee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a71
+    30
+    93e320d01033928d;
+  c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    406a6136512061f7080cc07df0591d8fa21f2dd88374d8cd
+    ba4c9972985a3777;
+  e8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731eb
+    fedd4705e505da1435dceaa7b1cc49ae1d50c3
+    fb945bb5060a692c;
+  8201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa33498
+    ""
+    33d92d711438bf90;
+  29b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a
+    22
+    d387a2b3add24161;
+  260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22b
+    b02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2a
+    200579382f8fefd7;
+  ebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98
+    ef1f0446b42fb144d44b6d00f06dc188d472a7
+    72b14ddabaa01c99;
+  84e0c6f21195a3b9f4ae985511265febd11c16
+    ""
+    35d8b20b8aedd4c5;
+  4720eef9eb1c8dd0b00951f284649016ed0045
+    63
+    3c8051aab08b5e2a;
+  31854bc78bf43966eb0cfa9138ddc399084456
+    08fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126
+    d71ceb7b023f4a2a;
+  b807e6daa089c3f9099c5ffb824173d7634c04
+    226f30cbb7f0e4a973a8cd190107314717a774
+    7cb1fd4850d2b1cb;
+  56f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9b
+    ""
+    8db7f9520ec921d2;
+  c597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9c
+    e0
+    53c35ba18d421787;
+  21a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18c
+    bfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458
+    d6409d3b48a62658;
+  cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957
+    f4b03cf43e89957f9a3e8128f8743d16687b7b
+    9ffecd00a5ce33b6;
+}
+
+rc2-ccm {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268ee
+    ee5332
+    ""
+    ""
+    ""
+    0e756e3d;
+  85a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1
+    371206
+    34
+    ""
+    ""
+    88075561;
+  c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a61365120
+    61f708
+    ""
+    0c
+    e4
+    677a1fdd;
+  c07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f50804
+    6733d9ff61
+    cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49
+    ae1d50c38201a894476b3f102b752eb9529533966f27043e
+    aa2e353749ab572e5ea55be5be368bae0ca3cd5604ec9c06
+    bbdce19a0df3c05b;
+  b621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a
+    97a48030370c33d090c54215abd6b3ad54efc9
+    a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac
+    a1b2416f66d57ca9034827ff55b17cfac62108e8a10a62c3aec1de6d6a
+    af60612dfed6edb3;
+  26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c
+    6b08ac
+    ""
+    ""
+    ""
+    ef7e40ab;
+  8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e79
+    52d22b
+    b0
+    ""
+    ""
+    9cef3d08;
+  2d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd
+    52147e
+    ""
+    d1
+    a9
+    0e3165e9;
+  2ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d1
+    26b807e6da
+    a089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973
+    a8cd190107314717a77456f3ff669c732b58db8f48af65f7
+    79a7ec7b8d3aad1c29ce22222d9089766c6892e25284af53
+    1a749a4b280e03eb;
+  cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957
+    f4b03cf43e
+    89957f9a3e8128f8743d16687b7bb8deb9bd20
+    5b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac845139958701
+    c1255583506986b100df1504190df39ec531be3506347bc3db4ab4ec82
+    993490ca3359ed04;
+  1677508a15dde524af3e2bee0646541a42c2ec
+    ccb44d
+    ""
+    ""
+    ""
+    2848a767;
+  65bad397abfaf529ee41cf9a05c7efedef3401
+    539c51
+    d2
+    ""
+    ""
+    e0651099;
+  a90bbf7f1bfc338ab0ef5746ea8fdcccd213e3
+    3f7e8a
+    ""
+    57
+    a9
+    9135e83e;
+  18fd25014107c8e7d715a92add9589d1f5c054
+    b2d9835146
+    05ec590294a319b9802068a9f891bc5ba5afabf8c3122d12
+    d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe07
+    a0219d75977a704b34340dae9a6f96be4baaa1ad3ee96afa
+    b1e6a4f9015ad908;
+  9753ee1a957eb6d6699e6b7ea2725cb2dac07e
+    cde95759ac
+    46fee6dda7abc8ad68daac90cfe22d2f1f2968
+    cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d40
+    612f7d0ab987bbd987e78707fa59388a40cd95b609e3b0df2298712134
+    242d9a4c7c587d14;
+  5e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b954
+    60938d
+    ""
+    ""
+    ""
+    9ebdeb8f;
+  e1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186dd
+    f1f6a7
+    a3
+    ""
+    ""
+    c53713f3;
+  aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba600
+    768175
+    ""
+    23
+    ca
+    704b73f9;
+  bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a833
+    1f0a170b66
+    283e4f834a06148f302c3973accd56f6f24e33958b8c2e23
+    52fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48a
+    49e3c85b0d02dd9f89914d75405cfac2f343deccb9d98391
+    95c00f9b22962366;
+  fa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315
+    799dc875fb
+    a578c8ec4837898a92142b5b0677da1ac27311
+    7b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d
+    8eccebfa67d50519fadda30deee9c4d16575a61eb68adf6157271bdabd
+    1dbaccd5b26fc6e2;
+}
+
+rc2-eax {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268ee
+    ""
+    ""
+    ""
+    ""
+    493b1fd04ede5d08;
+  ee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a71
+    30
+    ""
+    ""
+    ""
+    21a99e853cf8d624;
+  c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    ""
+    40
+    ""
+    ""
+    c2a4952faeb51fe5;
+  6a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    ""
+    ""
+    60
+    d2
+    bf5432b8192d764c;
+  57acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f10
+    2b752eb9529533966f27043eb621b7f65b000961040ef2f9
+    b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57b
+    f9c3cc1576f674b14e65fbe890be777d513381d3fbfaf3b6
+    3b7bbf2f56718d0b;
+  b3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    aee2b03fb648e2
+    7fff63102758fe2b69ac26afa3349829b94586
+    306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474
+    8d354144a9ae2bfb22f92a7c7bc3655d62b2b56d972a0b48fdc527118a
+    168314d144ee4c2f;
+  fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836813111
+    ""
+    ""
+    ""
+    ""
+    8e3a0ea494b5dd15;
+  5c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af
+    58
+    ""
+    ""
+    ""
+    3bb40705efd17087;
+  13b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d4
+    ""
+    4b
+    ""
+    ""
+    02dc7bc996b3d08a;
+  6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973
+    ""
+    ""
+    a8
+    46
+    593604619e5f140b;
+  cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd
+    409b687fa3a6827b
+    480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a
+    3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cda
+    b775f9f9970f69be179df624ffa0a971fd60e1a77897730b
+    1f3bee3056b77bef;
+  d9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319
+    b9802068a9f891
+    bc5ba5afabf8c3122d12d7ff3c41122d70d17d
+    4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea272
+    e4ad70206a32030a723a97c5fa7c051f0e47e4c419567c9f2465e6082b
+    b4e14cf29446000e;
+  5cb2dac07ecde95759ac46fee6dda7abc8ad68
+    ""
+    ""
+    ""
+    ""
+    e48136f1558ef9d4;
+  daac90cfe22d2f1f2968cc42fa8b669ed3bb35
+    42
+    ""
+    ""
+    ""
+    75a875a6cf6822dc;
+  a9cf44bbc8c6254d980398bd94e66eb4563d40
+    ""
+    5e
+    ""
+    ""
+    aff6510c3cfc9cf8;
+  51881e99027b8ab9aea3ccf860b0009740763d
+    ""
+    ""
+    96
+    73
+    0fbcddfb90453138;
+  836c5f87b95460938de1288c69d80ea12ff4bb
+    5f069b8a2e86041c
+    1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b3
+    5b15ffaa6c36800d9645563a308ba60076817523bd2abf12
+    8c0f4a82cdc742cf10c6bcd81f08fe54d44602b6b04d84cb
+    6048b808054d2c5f;
+  61b089d8f23a9c2835076a23faac2cdd67771c
+    c667a8331f0a17
+    0b66283e4f834a06148f302c3973accd56f6f2
+    4e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8
+    b136f77a805e9042723b12db98a1ab0c8af27b687ea3b81bd09cf15d20
+    94b18788b3964b32;
+  f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c48
+    ""
+    ""
+    ""
+    ""
+    441faa27cc4c5c56;
+  6315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b
+    45
+    ""
+    ""
+    ""
+    eae3c4243cea46f9;
+  bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d
+    ""
+    38
+    ""
+    ""
+    9a3430a79df38876;
+  0d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf
+    ""
+    ""
+    66
+    2c
+    0cb5f535e70f4099;
+  fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe4
+    26a5a0e80f678d40
+    4147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959
+    b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f
+    6a855a701998a62f385b9ec42102a67ef354925d18569dd8
+    eac5dfe4f5cbfff8;
+  5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8
+    556b7aa7769459
+    48d1b8834df2196c92ec1718dcdeee0d52d953
+    9726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfb
+    9cf8b628ab6c3e8c69c289c3564027ff0de5e6bcecc38c05b8d1b7ec0a
+    fd274b8e3c469eb6;
+}
+
+rc2-gcm {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268ee
+    ""
+    ""
+    ""
+    ""
+    359ae96bacf96c86;
+  ee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a71
+    30
+    ""
+    ""
+    ""
+    b106f982ce0fa16f;
+  c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    ""
+    40
+    ""
+    ""
+    83c2efaff3e6fdf8;
+  6a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    ""
+    ""
+    60
+    c9
+    dcac5bc0a6fc80b2;
+  57acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f10
+    2b752eb9529533966f27043eb621b7f65b000961040ef2f9
+    b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57b
+    9c8dd0c92811769d381b46a75e60b5d80aebe054d178080f
+    bae3d5a852937cf2;
+  b3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    aee2b03f
+    b648e27fff63102758fe2b
+    69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72
+    24efd192d24c0a27bb0453a186632e8084dee9028fd647362aa26cf46ed118f682
+    1505f15227faa14f;
+  807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b
+    77dba189196d1e
+    bba10b0467cb9fc2712a199e533fa9156308cd
+    ec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c
+    fe9f005b0bbe7851e82e3e55aadc6fa3297c4dc6aac7da88eea83d77c1
+    ca6d92a0f8474851;
+  571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    ""
+    ""
+    ""
+    ""
+    644405a0cd8f478c;
+  7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52
+    14
+    ""
+    ""
+    ""
+    986911f8fb61ffd2;
+  7ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc84
+    ""
+    24
+    ""
+    ""
+    55348e0c9fadf225;
+  d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc17
+    ""
+    ""
+    70
+    63
+    399484cb038779bb;
+  a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee06
+    46541a42c2ecccb4
+    4d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2
+    a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718
+    c734efcfe1131a326af5fd518ab1033e7ffd7c4eb825b4c1
+    8255ef3dc1ff72a3;
+  fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b66
+    9ed3bb35
+    42a9cf44bbc8c6254d9803
+    98bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f
+    7b2425dc58e780f0ab6b356cdb6ad2223d2dd69372109f08203100aa9095ec1551
+    094f16bdf157a900;
+  87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33
+    958b8c2e2352fd
+    61e4fa8fec816ac861a8b33779f09e7a10fc02
+    a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c4863
+    1118c134e5ab39c5332fba8f3e0a566361c72bc4fd4a14219400ac57e7
+    b8a684bad429d427;
+  15799dc875fba578c8ec4837898a92142b5b06
+    ""
+    ""
+    ""
+    ""
+    441a5fc1a7aa3965;
+  77da1ac273117b45bcfff5d5f8b6fde2893232
+    a9
+    ""
+    ""
+    ""
+    c2d97eafb2d4dec5;
+  f81d14517ffae475f6b94a43a67b3d380d2f9a
+    ""
+    aa
+    ""
+    ""
+    137e2f9a5fbfaed9;
+  fe2dd721c0095c8808847689211450ba8095ff
+    ""
+    ""
+    ab
+    8e
+    1499fe34d82b9009;
+  1eaadf66fd22ac1976063e113ab61f813e28a1
+    397a7974a1d7f422
+    0c785fe426a5a0e80f678d404147842941feeffdc2eb44dc
+    8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e515
+    46c4eff1fd15b9be037e2e240b8845cc9e7e2530ae6214ea
+    9feaa7393f439893;
+  0686d2301b43a15a84e81d7f5cedaa49e2414e
+    bf47970e
+    560475cff206877de69146
+    acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726
+    7af0b728198469b00a3792e3640858ea8e10f4f9a0ee2f97b007f3961499d92d0d
+    1d5b27a15b866945;
+  d2810391b3f9d10c39b07ae8f08ce7cee4758a
+    386a9943e97ded
+    fbe61e737882cd09c2b9a80f34c0fde11c2481
+    b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe084
+    dab65bbaad4fa9e2aeee14886c89799acfd26a90de80cd6851f05113d3
+    c547859e516e9528;
+  85290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb
+    ""
+    ""
+    ""
+    ""
+    666def937cca91b5;
+  6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91c
+    b9
+    ""
+    ""
+    ""
+    cb3f188911d99a1a;
+  d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0
+    ""
+    d7
+    ""
+    ""
+    223747afb3570769;
+  cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3d
+    ""
+    ""
+    f6
+    f4
+    6ae1ee13e1831acb;
+  c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d1
+    92ee53b3f3ebd66d
+    dd98cedbe88e245de25b1593b70f8601562d90a9b59ed034
+    a867642d25d54756fa5c47f16f64b837bb4926214211a1c6
+    d995a4197fa15265ee44b445bc0d3940c486f9c34ba9077e
+    0b047045426e23e6;
+  96ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0
+    d5ae7be8
+    dbf98e4ffed2cf6b1372a5
+    aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b9
+    a4ed2fa0d3f42b2c3270ac0801aeaa7f28f57b101c8a9a1c0e45a046e9c6887b00
+    4c3c11a4709bcf9c;
+  6856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597
+    a1406d465b7b14
+    19ea51cf858f938f6daafbd656445a09898eaa
+    96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669
+    a1a0fe6856d107a0b49d164b72c0102a06bfc6ea17723f7587fab4808c
+    d797a4abd2ac973e;
+}
+
+rc2-ocb1 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268ee
+    ee533285a6ed810c
+    ""
+    ""
+    ""
+    1a9b5d9930de70b3;
+  9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9
+    519848a877ff77bf
+    79
+    ""
+    ""
+    c8a18423542f2476;
+  192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8f
+    a21f2dd88374d8cd
+    ""
+    e8
+    65
+    1ad7745b69b0db1f;
+  e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfe
+    dd4705e505da1435
+    ""
+    dceaa7b1cc49ae1d50c38201a894476b3f102b752eb95295
+    702a8f6236f63b37d12754e285b48acd278a5dd319781c47
+    4aed0840ec1cbc36;
+  33966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb5
+    7bb3a4f3ebbbb18a
+    c6c95a97a48030370c33d090c54215abd6b3ad54efc9a383
+    78c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe
+    63872e8fa08cbc02a9b67199cf4f8e805df8021d7dc7b857
+    7dc44cfa7b6a75c1;
+  2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474
+    fd71d891f24bb65d
+    ""
+    1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba1
+    0e8b2f665c8e05920b18889a94a59262da8d5511e504ff00740151570d
+    aa8fbbd1631944b9;
+  89196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f530
+    6ceb0c6b08ac8b0a
+    22260c571b4a42bb8fdb233bfa6a5cfb0bad7d
+    95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5
+    fa9b97df764582e8b06700b70f488912e52bb40512b7e82546c98beea3
+    6125dbe65becfe77;
+  b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d07983
+    91805da08da3aefc
+    ""
+    ""
+    ""
+    201550d036fd21c4;
+  5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae9855
+    11265febd11c1647
+    20
+    ""
+    ""
+    980aada67611e269;
+  eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e17
+    21b730374ffc9bc5
+    ""
+    97
+    a0
+    772be2781de4d5f1;
+  f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d
+    16687b7bb8deb9bd
+    ""
+    205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac
+    935c1246b3c54e88b1612b1ae91add5d006c1da2eee504bf
+    cb750259096356be;
+  8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3
+    122d12d7ff3c4112
+    2d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a95
+    7eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7
+    e934e27dfd22901f7dee3fbdbd8380d67e381b1b0a969ef5
+    00818ef2133898d7;
+  abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa
+    6c36800d9645563a
+    ""
+    308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67
+    2d45ecd08b4263bcdcde76394694aadf336f30ba6b70a6109cc0c01041
+    e1d92d792d66bbd0;
+  771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fd
+    e2893232a9f81d14
+    517ffae475f6b94a43a67b3d380d2f9aaafe2d
+    d721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e
+    801610881c1b88c3db1db411c93abbac039ff78a579e99226ebecc9b95
+    21d1073d1325dd61;
+  113ab61f813e28a1397a7974a1d7f4220c785f
+    e426a5a0e80f678d
+    ""
+    ""
+    ""
+    4366d16a510e7a2d;
+  404147842941feeffdc2eb44dc8c0d5e8f444f
+    7f4e0c893959b74d
+    c2
+    ""
+    ""
+    71128105ccb95e0c;
+  3a7bb40e7e0013e5150686d2301b43a15a84e8
+    1d7f5cedaa49e241
+    ""
+    4e
+    7b
+    2f6c2965368d5936;
+  bf47970e560475cff206877de69146acc3ab6c
+    f8556b7aa7769459
+    ""
+    48d1b8834df2196c92ec1718dcdeee0d52d9539726d28103
+    3ab97a491b334616b5320f00b70e5e3620d36e5286b74ca3
+    d3584dde26228442;
+  91b3f9d10c39b07ae8f08ce7cee4758a386a99
+    43e97dedfbe61e73
+    7882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a
+    9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d
+    d9fe5001eec9f51d5650f640a1acd392b3eb4cb1edde5d31
+    b9c26d9e3edb786f;
+  87d13b07398a1458c2c6b61dbdbc1cccada8c1
+    a0a9aabb6c4e3c35
+    ""
+    54f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7d
+    3a35872aae6ecc5f2db7d75ba96b45d22646c61c41ecaa1be26c4685d0
+    9f54725515309904;
+  e74fc9a9b37154ce6c0b396179d31f06a1dd59
+    82cbc0d7cb23841d
+    a1ae8f4ae480cda98ad6cf2bacf6f9fd3f8213
+    30c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c9678
+    595e1b17cf4e6f603f4f37c5cc9f95960010ab062be907ea011276f6cc
+    6cd3322bc4f3e0ec;
+  8d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601
+    562d90a9b59ed034
+    ""
+    ""
+    ""
+    39204a02c689b225;
+  a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba17
+    2010abb433922a22
+    d9
+    ""
+    ""
+    050a3b74030d78b6;
+  fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b
+    1372a5aa47b54fd9
+    ""
+    d7
+    f7
+    c80142d220c7ce79;
+  0c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b9
+    6856beca34fd6544
+    ""
+    bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b
+    a317166b0030c8c02542e56149c7169f92667fa0f1825571
+    e1f6c6acb9532013;
+  7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e3
+    1e4e34c94b8bfae6
+    4825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d0
+    99f47166edf54538e88fbf433a7ff212085179e79771f6ee
+    bf9a3249cfaef471b99720132fe379a074cc10927ed689fc
+    f60b7355eb51cac1;
+  e7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e
+    771702fb1901ecfc
+    ""
+    8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4
+    287fa9c3540fc7adbfaf8a35cb932dbf3ec8be9b1c40ab18d34b1f82bf
+    a1789324aa8ffae5;
+  cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2
+    367f047265264e0d
+    a72efe8995e6c932a17eab511eddb8e4ba463c
+    663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088e4
+    f2433dd6f072fe804e258d6facf08e8798a615510c1cd0f1283f7b172b
+    b4cee725242787cd;
+}
+
+rc2-pmac1 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268ee
+    ""
+    0e2341b111c8fa18;
+  ee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a71
+    30
+    73e15def05b8727d;
+  c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    406a6136512061f7080cc07df0591d8fa21f2dd88374d8cd
+    9a5cf16bab880541;
+  e8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731eb
+    fedd4705e505da1435dceaa7b1cc49ae1d50c3
+    0573bcdf6c429f04;
+  8201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa33498
+    ""
+    5fc03971d7234498;
+  29b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a
+    22
+    d334d7d0dd6b420b;
+  260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22b
+    b02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2a
+    51b4652c5715fba8;
+  ebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98
+    ef1f0446b42fb144d44b6d00f06dc188d472a7
+    c288ffba6c151611;
+  84e0c6f21195a3b9f4ae985511265febd11c16
+    ""
+    2787117c93c78272;
+  4720eef9eb1c8dd0b00951f284649016ed0045
+    63
+    b9f64461b055f56d;
+  31854bc78bf43966eb0cfa9138ddc399084456
+    08fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126
+    dec9356cff25fd20;
+  b807e6daa089c3f9099c5ffb824173d7634c04
+    226f30cbb7f0e4a973a8cd190107314717a774
+    f7be51b3498189d3;
+  56f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9b
+    ""
+    69b721838992f955;
+  c597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9c
+    e0
+    27583a3b6ce6eca6;
+  21a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18c
+    bfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458
+    03e79dfa55f427b3;
+  cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957
+    f4b03cf43e89957f9a3e8128f8743d16687b7b
+    2eb16505976b0bf1;
+}
+
+rc2-ocb3 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268ee
+    ee533285a6ed
+    ""
+    ""
+    ""
+    581f918026a62a86;
+  810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    34c9519848a8
+    77
+    ""
+    ""
+    0f2f73159c7260d2;
+  ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07d
+    f0591d8fa21f
+    ""
+    2d
+    af
+    f64c74ec46bb90b1;
+  d88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3
+    e98787
+    ""
+    31ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a8
+    055814531dcb494c81bdd40c6b320ac9cdf3f6b48b3e62ca
+    9624c68017513bf7;
+  94476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52
+    ebfda19d0c
+    cc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33
+    d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    7dbbed27e29a669ee60e79d868848e797cf8d585fa877eef
+    b181420c050f46bb;
+  aee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600
+    157846b710ee
+    ""
+    72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d
+    d2edbee66b1039b346ad18f087e5712227159fa306a398b03c5805ebaa
+    7f3a208c993f1401;
+  57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f
+    768281e040a9
+    b9a222bd689aef66f5306ceb0c6b08ac8b0a22
+    260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836
+    a7d224261bc9eed46f062bad5ce6acf20db49e5efa965da235a6cbfcf2
+    800f8ff9dbcbfcfb;
+  8131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451
+    dcd1af5813b7
+    ""
+    ""
+    ""
+    abdbde1d369f81cf;
+  0d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d
+    00f06dc188d4
+    72
+    ""
+    ""
+    8a82cb9899ea8c5e;
+  a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717
+    a77456f3ff66
+    ""
+    9c
+    e6
+    0d8c6497b6eae6d2;
+  732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84c
+    ef64f6
+    ""
+    c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b
+    49ef16eee0810eecd3e8dab4f26ab52a367325b186d5829e
+    1703b30f19f8fd57;
+  7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1
+    f5c054b2d9
+    83514605ec590294a319b9802068a9f891bc5ba5afabf8c3
+    122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d558
+    6d390ba093cfe6c87e7d319eb6aa78bad09fc27ef0901b6e
+    44577228a64debfa;
+  9bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a
+    2e86041c1b9f
+    ""
+    c214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c3680
+    7c69cf94aeefeb59424b9cea58a906052733cd4218668705ab2853691c
+    e4f0891347b99255;
+  0d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c4863
+    15799dc875fb
+    a578c8ec4837898a92142b5b0677da1ac27311
+    7b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d
+    625cdc216187b9b9c5fa391d280bfa6b305ba1cb1fdd3724d8a72e1ac7
+    519207d1413a1b4d;
+  380d2f9aaafe2dd721c0095c88088476892114
+    50ba8095ffab
+    ""
+    ""
+    ""
+    06cfa98d411047e9;
+  1eaadf66fd22ac1976063e113ab61f813e28a1
+    397a7974a1d7
+    f4
+    ""
+    ""
+    175d23bbcafb83d7;
+  220c785fe426a5a0e80f678d404147842941fe
+    effdc2eb44dc
+    ""
+    8c
+    58
+    5468b08a313669e1;
+  0d5e8f444f7f4e0c893959b74dc23a7bb40e7e
+    0013e5
+    ""
+    150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e
+    ad2f294aef829753411546662ae01fb4b8c949c124b4a49b
+    6d43da0bc3eae79d;
+  560475cff206877de69146acc3ab6cf8556b7a
+    a776945948
+    d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391
+    b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe6
+    52df344f60bb655ce1efadd2bd8aadb58cba837a06a85693
+    dfd8c77383ca55f1;
+  1e737882cd09c2b9a80f34c0fde11c2481b11f
+    c76bfa4dbf71
+    ""
+    0a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07
+    8be902be354731e8231299e1b2dedaae4690ecf8089199e6cec95b6123
+    0f45a8eb852e5baa;
+  398a1458c2c6b61dbdbc1cccada8c1a0a9aabb
+    6c4e3c3554f8
+    fb1ef61614c270295dfc0ca6551ca4bdb75359
+    f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cb
+    3fb468bbadc6a29bd6281da179066d2ade7be03df9c6b383c8e8c13546
+    b26515dac888c01c;
+  c0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c4
+    3f3df6c2b3fa
+    ""
+    ""
+    ""
+    34bd44dbfedfadb7;
+  c7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53
+    b3f3ebd66ddd
+    98
+    ""
+    ""
+    30e8cb9e8b9c5270;
+  cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25
+    d54756fa5c47
+    ""
+    f1
+    0b
+    a2ccd20dc938026f;
+  6f64b837bb4926214211a1c696ba172010abb433922a22d9fd8815
+    19165e
+    ""
+    b9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5
+    68cd0332b59dd009fe414fedbaa6e5db5617a72662f17e00
+    e56e28e0835cfe53;
+  aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d
+    64f2ed6a29
+    b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3
+    001da597a1406d465b7b1419ea51cf858f938f6daafbd656
+    14eba6942ae06ed78cf099b84112f9a14ef047a66bc60759
+    8cf160f02394665d;
+  445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d8
+    8eedb969ffe0
+    ""
+    7669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff2120851
+    6d2c904a5679e677bb5388b0fd803942da8009ba69144d90adeebbbd9e
+    9bc08b7a451dab64;
+  79e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70d
+    da7a4ca2a25e
+    771702fb1901ecfc8a959cb8e75079bb018ccc
+    8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c
+    7e6523063d93c71b5e3843e7e1db47185be88cd6e59983a344ccaa55f3
+    de2d08e85152d02e;
+}
+
+rc2-ocb3-mct {
+  16 cf8c7167477a5451;
+  14 f7b6b2058ca5db46;
+  12 249d762b7fef3e0a;
+  10 a6d5f268d2dc063d;
+   8 760827c7117d67ef;
+   6 4acbb3854f8a4d2c;
+   4 9165027bf9b60335;
+  16 06ec3efc4156;
+  14 0b3b19c5b0a6;
+  12 8651074d6d12;
+  10 f2c5ce719be9;
+   8 d6646daf8e75;
+   6 70c48ce7d192;
+   4 61903ea2f3fe;
+  16 a9049697;
+  14 e4cdf5af;
+  12 5571a44b;
+  10 a9e735fa;
+   8 4179cf26;
+   6 4a83d2cf;
+   4 f50be88c;
+}
index e7a02c9..77daa31 100644 (file)
@@ -13,3 +13,933 @@ rc5 {
   dc49db1375a5584f6485b413b5f12baf 2f42b3b70369fc92 65c178b284d197cc;
   5269f149d41ba0152497574d7f153125 65c178b284d197cc eb44e415da319824;
 }
+
+rc5-cmac {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    ""
+    daf5b15f8e1e563c;
+  acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed5415
+    4f
+    da179047660f232b;
+  8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a
+    96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b9
+    0bc5dfb1ac40f05c;
+  7e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a8744
+    98ad0abef8bc4fcb70e27e98ef1f0446b42fb1
+    ba244301c8380eac;
+  44d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff677
+    ""
+    4c21b877018c36b9;
+  8554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d1
+    7d
+    3806f9d4de532103;
+  4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c
+    3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac8
+    a23a44e7657e986c;
+  61a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cf
+    f206877de69146acc3ab6cf8556b7aa7769459
+    e4b7b2e862a7a773;
+  48d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee475
+    ""
+    f0b878ae4b245d7a;
+  8a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e
+    0c
+    6f07948d34c807ed;
+  536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1
+    a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551c
+    3b56f732d29bcda8;
+  a4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb2384
+    1da1ae8f4ae480cda98ad6cf2bacf6f9fd3f82
+    28c46ab756a75864;
+  1330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f1
+    ""
+    08523dfcb089cd8c;
+  6f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59c
+    c7
+    26a7e390109474a1;
+  83443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae648
+    25ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099
+    841195a80291401c;
+  f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8
+    e9002926ad0284c738f4cb0f58a1e34c8b15ad
+    029a65f6ecedeaec;
+}
+
+rc5-ccm {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    acc876
+    ""
+    ""
+    ""
+    7c254f77;
+  38f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28
+    523c03
+    d4
+    ""
+    ""
+    1bee7cd9;
+  de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca3
+    38527e
+    ""
+    f1
+    b4
+    2a4035c8;
+  9b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa
+    69a4cd5214
+    7ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f04
+    46b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9
+    27b471cdc900d7c1cecdbccbe0c791d0894881688285dc18
+    0c52bf2c8519e396;
+  f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021
+    a5f1fa4ffa
+    91544485f1a1258b2b9b8f0911e32d65cc1770
+    a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948b
+    4c97911b3e34ed74ca84d41573f434210e43911778a77caa1bb64b5d52
+    329a8ae6ba7b6150;
+  dd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a
+    957eb6
+    ""
+    ""
+    ""
+    83c54227;
+  d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec81
+    6ac861
+    a8
+    ""
+    ""
+    d11cd472;
+  b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206
+    877de6
+    ""
+    91
+    d7
+    75a2a5f9;
+  46acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3
+    fac7cbcf96
+    523d4723f91801325eb8553236651c96788d73d192ee53b3
+    f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9
+    740ab29287b8db09e16309ab92186c430c2c71905ef788db
+    16ed39d411395c7f;
+  b59ed034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283a
+    b178ef2b80
+    0d7b969da05780ffc1ba78c70dda7a4ca2a25e
+    771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e900
+    b630304c8082405cd416ec56b4b32cd188cb81075a1df8e7ded7042e84
+    15c392aa9df0ff73;
+  2926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2367f0472
+    65264e
+    ""
+    ""
+    ""
+    5c63c12d;
+  0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961
+    dcfd40
+    08
+    ""
+    ""
+    8ec0a5a4;
+  8d5be74088e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d907eab
+    7707ca
+    ""
+    48
+    61
+    d74da629;
+  ff5ba1ae93d16225d469de5747bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535de
+    d56112d6e3
+    d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a
+    8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374f
+    12ebdfc275cb1ad1926629dec9765ecde238384b6b77aed3
+    91dd4e2e2acf63f7;
+  c43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7e
+    a9c7c9cf54
+    f3bc6d94238ab56d738e02abd651477cd726d6
+    f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a
+    a0cbde9a036ed8857dec5ad4dce61b29ec4a9c304fe386afefe3aee97f
+    84fbd4d0f0710fea;
+  8733b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad09a5b8fa687ec3bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b612ea37fc5
+    cc09f7
+    ""
+    ""
+    ""
+    b8580130;
+  f62f66b423fcd2dec5de24d264f2c839839c1b06319f687dbc68d9f07fd41ccb4f8cde8de201ec2680332bbded4883deea0b58b54bdd13c17ef292b0ded3caeb5e57fd21df10bc6186265ee6ea
+    45907d
+    e6
+    ""
+    ""
+    aa6fedbc;
+  cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945d83f923e66b0a6689cf0969c00
+    3a8fca
+    ""
+    80
+    b5
+    0b3d21e2;
+  e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee78ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592
+    c172a5cbc1
+    9456c95c1bea6079f3867e52d663cb3884b2a0a8ff825df7
+    52423f3179bfeb89eca385f20ddce5f1f23564672e370ffc
+    704a2f85040f89ae682fc9fe222d1514c8a6ee4c83621978
+    bd37c7f24ffd34dd;
+  37d400a31e8aac1d426ce10df73c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6de738721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d9
+    3d1f8fcc53
+    574427767396322b3bf7d02cec05093696cec0
+    7591ada462271b1d1519eedde0df37a330fe8c22ebd77705917b7e32ae
+    a81b6872abcb10bf73091054448aa06f5713d2da96a21467a86272aae7
+    3acb5a6ac60a7d69;
+}
+
+rc5-eax {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    ""
+    ""
+    ""
+    ""
+    b6a3c65665d9698f;
+  acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed5415
+    4f
+    ""
+    ""
+    ""
+    28e0ed64beb3636e;
+  8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a
+    ""
+    96
+    ""
+    ""
+    4e86273646b6d548;
+  ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b9
+    ""
+    ""
+    70
+    e2
+    b61886a4345f760a;
+  e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107
+    314717a77456f3ff
+    669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9b
+    c597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc
+    c1032a72ac5e8845a7d27deae33795ccc3bf3caf3e3cb94d
+    ac40d28502442851;
+  0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf
+    9a05c7efedef34
+    01539c51d2a90bbf7f1bfc338ab0ef5746ea8f
+    dcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2
+    bf3cf0b9900f40e42643c19226af6cff9d221051ab7a52e22bdb0343d0
+    19e314d1c9556ec7;
+  d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261
+    ""
+    ""
+    ""
+    ""
+    3c01672989b90b3d;
+  b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147
+    84
+    ""
+    ""
+    ""
+    ec812e10e0061171;
+  2941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551c
+    ""
+    a4
+    ""
+    ""
+    f87f9705308d2757;
+  bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b9
+    ""
+    ""
+    68
+    2c
+    ecb3af42ad5aaf5c;
+  56beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2367f047265264e0da72efe8995e6c932
+    a17eab511eddb8e4
+    ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd
+    40088d5be74088e4097efb0368c7e2f431ee6988cf2a0e9e
+    097489eca92aa5642b549cfac254a0084e6392328b287f68
+    1e35efa371fa0754;
+  beb3de79c4f86c9e4fba61339d6d907eab7707ca48ff5ba1ae93d16225d469de5747bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd651477cd726d6f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a8733b2cd2df9d1d905cfdb29983050d6
+    bcdb686a0c8970
+    31ad09a5b8fa687ec3bad8e18dc2ad361f1e22
+    6e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca9
+    faaae6078a435e40c355d6cb7522b57d1d2041d016be50c0499a94a4c9
+    d37dacc2ee37665c;
+  1b612ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c839839c1b06319f687dbc68d9f07fd4
+    ""
+    ""
+    ""
+    ""
+    8e0d69b365dcd5f0;
+  1ccb4f8cde8de201ec2680332bbded4883deea0b58b54bdd13c17ef292b0ded3caeb5e57fd21df
+    10
+    ""
+    ""
+    ""
+    70b4543f8437c930;
+  bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f
+    ""
+    02
+    ""
+    ""
+    7b962a2f0a36c218;
+  56b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945d83f923e
+    ""
+    ""
+    66
+    d3
+    e3934e8cf3dd1e43;
+  b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636
+    845dac557bb3e75f
+    3a18fb8e173416867fcd0ee78ddd9236beec76d55ed58b10
+    f91d07a037791ab96e83c4bf2fb5b205e592c172a5cbc194
+    1c11e3e723c447062953918da6c2935a8f736ba211e02110
+    26cf3b89bb9216cc;
+  56c95c1bea6079f3867e52d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1
+    f23564672e370f
+    fc37d400a31e8aac1d426ce10df73c5ee478b3
+    b63d91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6de738
+    76d660c82fe87ec1fe0ae671550a17ecff0c9e771db2949c1b786f1cf2
+    740fccf37358c969;
+  721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d93d1f8fcc53574427767396322b3bf7d02cec05093696cec07591ada462271b1d1519eedde0df37a330fe8c22ebd777
+    ""
+    ""
+    ""
+    ""
+    cfff0e086dd13bf8;
+  05917b7e32ae88f45a34a8ba3037235e19a394be4d26ce47317d8087684456b4cfc5555e925e3e7b2ebc829b2d0505ea617b0ca9531bcdb96040d39040e632d562643ccb64286303040fcaf679
+    e9
+    ""
+    ""
+    ""
+    1e93f551fac620d8;
+  14eaddc05af8843ce6a427b99a5dc266de31c09165237eeefe4b58cc034b9f099f04678c2a9da898b39324cd3087a651014f6796f9c4881d89e127e62221e47e57badd678d490c2f320ff8fb1c
+    ""
+    42
+    ""
+    ""
+    ea6e9288b9febdb3;
+  761bd439f3e96dc0ed1d5b2169912af1a4e2c533c52ba3e8c71c23a089e231480aa63c484fb34bd522397f102cb8ecf4f64e329884fe73be257a753b38200bc23f94a079bde2dd98d813655daf
+    ""
+    ""
+    a1
+    83
+    409170cbacd6adbb;
+  5b85419d15c41a5153cce5d0e8c8702db2ba11927589678d4f7b8fcfad4818c411f15f452300903874f9a532ee46496ae753a2340af7b91f9632fc5ae71ae18b40de751ab6b6761ca16434a993
+    5e466e11c1cb072f
+    32a59c313dba3db646ae909a096697d9a7b0556463ff1126
+    ebc43263391424d02739d0787e804d8f1dccf6c897a8a484
+    c9f82dea0b1b5fd479b0aeb37b717817455887a199312aa9
+    4e1d9e542a78d512;
+  31324324041b5302ccd501b538bd03d5cb5c90d1fd3f7d2be187a787032c79ed900764ee4ce1d3fc042c084f7d8c0c48ad7d6f1eabd0fd1ec24a88f26734d5c8d92dbd873a8fe113090d401bea
+    4d28ff49f10ff5
+    93adc258e091abd31b62dd1735158f98765970
+    acc6602da063aae01a2a199d3a4f37a5f062d216d2053a83b5d3a0488a
+    a9dc22dc5d57626720b7c1260c63dae59cbad790ac527d5a26e7d943dd
+    86f8915e2fdee1e3;
+}
+
+rc5-gcm {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    ""
+    ""
+    ""
+    ""
+    e2f61b7a5d2e1c0a;
+  acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed5415
+    4f
+    ""
+    ""
+    ""
+    8054b24c29fed688;
+  8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a
+    ""
+    96
+    ""
+    ""
+    db8e85bf23f737de;
+  ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b9
+    ""
+    ""
+    70
+    17
+    7c5e0036fc6b0768;
+  e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107
+    314717a77456f3ff
+    669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9b
+    c597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc
+    3549c431f3e7576dfcaf3130ec16f3f548704d727782677b
+    28148be1172ee6bf;
+  0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf
+    9a05c7ef
+    edef3401539c51d2a90bbf
+    7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add
+    3ff03565f741b63e12a647f755353af479b9f3ddfa1d50ff1540221f0bbb5c8b1e
+    81f81acac5371be7;
+  9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea1
+    2ff4bb5f069b8a
+    2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e
+    740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523
+    b0b28a3e099aecdda0b6756d2340184ab16df2c8cee22003ec3b783500
+    61d50b3d4e61fa34;
+  bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f
+    ""
+    ""
+    ""
+    ""
+    6133d10511794867;
+  678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c27029
+    5d
+    ""
+    ""
+    ""
+    25ff252aec8e0979;
+  fc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d
+    ""
+    64
+    ""
+    ""
+    68c3eb5a75e3992e;
+  f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2367f047265264e0da72e
+    ""
+    ""
+    fe
+    ca
+    187921ec9e1052c1;
+  8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d907eab7707ca48ff5ba1ae93d16225d469de5747bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d
+    94238ab56d738e02
+    abd651477cd726d6f3ebcd6fadeab50906642a7de6496247
+    060e7be3632ed9bd94bb42f45a8733b2cd2df9d1d905cfdb
+    ce458e557a153a69bff6fe3c4489c7a06e87dbbe31777fb2
+    b90acc3a3f31e693;
+  29983050d6bcdb686a0c897031ad09a5b8fa687ec3bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b612ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c839839c1b06319f687dbc68d9f07fd41ccb4f8cde8de201ec2680332bbded4883deea0b58b54bdd13c17ef292b0ded3caeb5e57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945d83f923e66b0a6
+    689cf096
+    9c003a8fca80e322a4b1bf
+    050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb
+    17a5e823d237aa01c73f6414d39d44b2f564a0dd3f1a07a2899a8051d1f0df8f39
+    36f636bbcbf9dd90;
+  8e173416867fcd0ee78ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592c172a5cbc19456c95c1bea6079f3867e52d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f23564672e370ffc37d400a31e8aac1d426ce10df73c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6de738721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d93d1f8fcc53574427767396322b3bf7d02cec05093696cec07591ada462271b1d1519eedde0df37a330fe8c22ebd77705917b7e32
+    ae88f45a34a8ba
+    3037235e19a394be4d26ce47317d8087684456
+    b4cfc5555e925e3e7b2ebc829b2d0505ea617b0ca9531bcdb96040d390
+    57f5a0f8d6415a8a621157e06114338900a5cd0837278b2751fc96da0d
+    5e3bc104eafa8f9c;
+  40e632d562643ccb64286303040fcaf679e914eaddc05af8843ce6a427b99a5dc266de31c09165
+    ""
+    ""
+    ""
+    ""
+    7810963d0383460c;
+  237eeefe4b58cc034b9f099f04678c2a9da898b39324cd3087a651014f6796f9c4881d89e127e6
+    22
+    ""
+    ""
+    ""
+    914c0d07b56a620c;
+  21e47e57badd678d490c2f320ff8fb1c42761bd439f3e96dc0ed1d5b2169912af1a4e2c533c52b
+    ""
+    a3
+    ""
+    ""
+    841a2c9697997e1f;
+  e8c71c23a089e231480aa63c484fb34bd522397f102cb8ecf4f64e329884fe73be257a753b3820
+    ""
+    ""
+    0b
+    05
+    8137867eb2cf4281;
+  c23f94a079bde2dd98d813655dafa15b85419d15c41a5153cce5d0e8c8702db2ba11927589678d
+    4f7b8fcfad4818c4
+    11f15f452300903874f9a532ee46496ae753a2340af7b91f
+    9632fc5ae71ae18b40de751ab6b6761ca16434a9935e466e
+    38b42c255ef96643eb10b3bc9f2691c2e99fce686f1f475b
+    c32a64eb29ba1822;
+  11c1cb072f32a59c313dba3db646ae909a096697d9a7b0556463ff1126ebc43263391424d02739
+    d0787e80
+    4d8f1dccf6c897a8a48431
+    324324041b5302ccd501b538bd03d5cb5c90d1fd3f7d2be187a787032c79ed9007
+    181bd0dc71010e424ebc9ef3076822ee1f476f71597408a6bed166e9d1041c5144
+    4752f2416b0d0b58;
+  64ee4ce1d3fc042c084f7d8c0c48ad7d6f1eabd0fd1ec24a88f26734d5c8d92dbd873a8fe11309
+    0d401bea4d28ff
+    49f10ff593adc258e091abd31b62dd1735158f
+    98765970acc6602da063aae01a2a199d3a4f37a5f062d216d2053a83b5
+    80090c15eefaee5a89856fb9a6e0d3754984998915327ea69facb3c3e5
+    67af4d834f3cdf11;
+  d3a0488ab0d2df631b2892cdfcf9fdd0f37de9ed67179aeae82fe00009428b297b553230a6d917fa0c1a233c9ebc8a4cba45b20543c540fc1b9dbce078b87a1534acf03897b95a3f372e9f6c5a
+    ""
+    ""
+    ""
+    ""
+    2f94915a82b486df;
+  5f2ae44a7dbce9ba43a39089de20de70d0544b5151db0a16e9769e8f2fc12c7f839fab269a0056284a697ffd4113a1cf43b5d5bdce2d86dead83f5a356e9106bedf908db61f1119f9700260ea9
+    37
+    ""
+    ""
+    ""
+    f02d5d46eab2e377;
+  9cc7232184d217158fee8ca42e75614739e9007f234fbcd86b0ad8f641a0449b6d9b0f99d1cb4a57a4d6f987feb0ade90aa1d81c4f497b3734be301da3e25fe692629db57311f422f3a1573f9e
+    ""
+    05
+    ""
+    ""
+    e3c6faf9bbec6f8a;
+  53a23e96265e4326fa532d7136863e5b4bc6c99ade3d4eb23cacdf6e42ad8ca13187eba1532920ba31582b3793b05fa65e9f80c5814b91f4d3c581c7b16c46b484859c6d19eebaf124681aa3be
+    ""
+    ""
+    99
+    50
+    8e188c981fa9757d;
+  43307fa4ef095ef8e7e50b703dc0420e74227c9351366ef8e98e1e24b48aa989dbb8d0f10471ae5428a6012fbe4f5cb2dab2863e574842cc0b3774e00dcfa63b0db1716c7e916a26fc2e198f8d
+    b63ab59955989497
+    782f16c5816270ef3fbe4ea22f484ddc12ec8f4bdbd6ebdf
+    bafb21fcf5427dbee5f95b53a0b4cb6d7c128b79f4657895
+    4a73ab00c6b33f577e36b151435331661e7a4f8ad2cf2424
+    3feaf9765a80ad6d;
+  f4b0ba518dd61436140f20d40224baac3a602da83cb254a7e03f052c63c1f3f00f301cc944a1789133bb8048f07dc123f2ca7e20c83988e4bfea6d561ab5aea542db544a14376d5d52f7265c7a
+    8d2fc4fe
+    ef99b9dba89eb472f71d8e
+    b5affe900d776e4cf74e52b6c86db981143082735c6473a86a5da3d2e8cbb8602e
+    f41bd01dcd02e66f0d3b4771c32053d11c302c6144fb40397bf548b21d6b748655
+    c0c9b188065fbe55;
+  bbaf08bf9315fba15f46714bfd2c8312fb5744dfe84615ddb93f15360161f2efb1fc39b8b6ad97427dcaa0435bee7f3a5c11fd01b9c120aa6004f84bcba838a1c33beb4087719135b355dce9ff
+    d6fd639f192e4c
+    2c9a2752bf74a3f63408d3b27df51f44ed5537
+    bfb0162f05edbad1b2c36ceec1dc407475b8e05fcb5ee66c7205f21804
+    7a28b08624230f3c25eac43abc77e6525efd4ccf45b72033af74c47021
+    70cf57e5e7d02c97;
+}
+
+rc5-ocb1 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    acc87638f5080467
+    ""
+    ""
+    ""
+    aa54e91505bc3ec6;
+  33d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de
+    1600157846b710ee
+    72
+    ""
+    ""
+    5e23eb9cc063fb52;
+  807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f
+    88de9fd41e72d7b9
+    ""
+    7e
+    14
+    8086d6e7472314d3;
+  23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498
+    ad0abef8bc4fcb70
+    ""
+    e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0
+    ace115dc9234795ceda92323b7555d9b7088d5f03851f5a8
+    ad07550f521cb01d;
+  c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003
+    cc0cae9ce021a5f1
+    fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18c
+    bfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458
+    9ef4ec1d3bd29e3da733811d8d32183a38e0c77c4fa209f4
+    e2244052d820e90f;
+  cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2
+    d983514605ec5902
+    ""
+    94a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d
+    568ebf6a8b3c3aa4bb11dfe4794a9b2dce157fc51ea99119a0b680fba6
+    a7720c81e5980c76;
+  4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d96
+    45563a308ba60076
+    817523bd2abf1261b089d8f23a9c2835076a23
+    faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973ac
+    b3118f057e88cb0db02cdb8fac8f78723937c596e56beeda7f56cc4098
+    90496eb2b1214b4c;
+  cd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43
+    a15a84e81d7f5ced
+    ""
+    ""
+    ""
+    c80dc735b4b0d91c;
+  aa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cd
+    a98ad6cf2bacf6f9
+    fd
+    ""
+    ""
+    e90954047fa57813;
+  3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ff
+    c3d1d2e31e4e34c9
+    ""
+    4b
+    b5
+    baf615ac4d6842ea;
+  8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c
+    9e4fba61339d6d90
+    ""
+    7eab7707ca48ff5ba1ae93d16225d469de5747bc1addf574
+    757d492944cb37a370da05afd0734e35c6bc4a0f970843ed
+    33e2b21461d5dd3d;
+  8729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd651477cd726d6f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a8733b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad09a5b8fa687ec3bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd8
+    4aed8aaebabb7e0f
+    24edfd9710b7bca91b612ea37fc5cc09f7f62f66b423fcd2
+    dec5de24d264f2c839839c1b06319f687dbc68d9f07fd41c
+    aefcbff3659b393a7cf6952eb2fd4ad464d1be5c0c13b79b
+    1ba057a604a1b599;
+  cb4f8cde8de201ec2680332bbded4883deea0b58b54bdd13c17ef292b0ded3caeb5e57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945d83f923e66b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee78ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592c172a5cbc19456c95c1bea6079
+    f3867e52d663cb38
+    ""
+    84b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f23564672e
+    19b818cf69f0e92cd5a9f539f91e73dc543141acde903d98a24e1234c8
+    a41bbb9bbe7c82db;
+  370ffc37d400a31e8aac1d426ce10df73c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6de738721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d93d1f8fcc53574427767396322b3bf7d02cec05093696cec07591ada462271b1d1519eedde0df37a330fe8c22ebd77705917b7e32ae88f45a34a8ba3037235e19a394be4d26ce47317d8087684456b4cfc5555e925e3e7b2ebc829b2d0505ea617b0ca9531bcdb96040d39040e632d562643ccb64286303040fcaf679e914eaddc05af8843ce6a427b99a5dc266
+    de31c09165237eee
+    fe4b58cc034b9f099f04678c2a9da898b39324
+    cd3087a651014f6796f9c4881d89e127e62221e47e57badd678d490c2f
+    f2bc32f9e6d98d55aa5631671de574e5b6e0e0e17a59f20f418d3555f8
+    6a92cb246769b913;
+  320ff8fb1c42761bd439f3e96dc0ed1d5b2169912af1a4e2c533c52ba3e8c71c23a089e231480a
+    a63c484fb34bd522
+    ""
+    ""
+    ""
+    6dcc9a87c6b58479;
+  397f102cb8ecf4f64e329884fe73be257a753b38200bc23f94a079bde2dd98d813655dafa15b85
+    419d15c41a5153cc
+    e5
+    ""
+    ""
+    62692c7d1e45c739;
+  d0e8c8702db2ba11927589678d4f7b8fcfad4818c411f15f452300903874f9a532ee46496ae753
+    a2340af7b91f9632
+    ""
+    fc
+    e3
+    bd2bbcb67cb7a71b;
+  5ae71ae18b40de751ab6b6761ca16434a9935e466e11c1cb072f32a59c313dba3db646ae909a09
+    6697d9a7b0556463
+    ""
+    ff1126ebc43263391424d02739d0787e804d8f1dccf6c897
+    4a7b3da4e48db3ad461bce3fa4e1eb8bfe3d5415b80884f8
+    e8e7fdcdb5bd4809;
+  a8a48431324324041b5302ccd501b538bd03d5cb5c90d1fd3f7d2be187a787032c79ed900764ee
+    4ce1d3fc042c084f
+    7d8c0c48ad7d6f1eabd0fd1ec24a88f26734d5c8d92dbd87
+    3a8fe113090d401bea4d28ff49f10ff593adc258e091abd3
+    7f77bf26d0ccc5527ce3a51a3802d09ea7817507df9dbaeb
+    64cd828bd8c60820;
+  1b62dd1735158f98765970acc6602da063aae01a2a199d3a4f37a5f062d216d2053a83b5d3a048
+    8ab0d2df631b2892
+    ""
+    cdfcf9fdd0f37de9ed67179aeae82fe00009428b297b553230a6d917fa
+    220fc76c73b6b558f327d88b2ceb3c28b23e09ab5b15757d041a66548f
+    99c4bfbe566dbede;
+  0c1a233c9ebc8a4cba45b20543c540fc1b9dbce078b87a1534acf03897b95a3f372e9f6c5a5f2a
+    e44a7dbce9ba43a3
+    9089de20de70d0544b5151db0a16e9769e8f2f
+    c12c7f839fab269a0056284a697ffd4113a1cf43b5d5bdce2d86dead83
+    129f452d3b69b5c33ce6507970c4f36352a7c4bf4e3d621185fa8ef09a
+    c7267b667c9d44bd;
+  f5a356e9106bedf908db61f1119f9700260ea9379cc7232184d217158fee8ca42e75614739e9007f234fbcd86b0ad8f641a0449b6d9b0f99d1cb4a57a4d6f987feb0ade90aa1d81c4f497b3734
+    be301da3e25fe692
+    ""
+    ""
+    ""
+    d59834fe604f12e2;
+  629db57311f422f3a1573f9e0553a23e96265e4326fa532d7136863e5b4bc6c99ade3d4eb23cacdf6e42ad8ca13187eba1532920ba31582b3793b05fa65e9f80c5814b91f4d3c581c7b16c46b4
+    84859c6d19eebaf1
+    24
+    ""
+    ""
+    0c9a3b106bc9bca6;
+  681aa3be9943307fa4ef095ef8e7e50b703dc0420e74227c9351366ef8e98e1e24b48aa989dbb8d0f10471ae5428a6012fbe4f5cb2dab2863e574842cc0b3774e00dcfa63b0db1716c7e916a26
+    fc2e198f8db63ab5
+    ""
+    99
+    87
+    2b28f9babe659513;
+  55989497782f16c5816270ef3fbe4ea22f484ddc12ec8f4bdbd6ebdfbafb21fcf5427dbee5f95b53a0b4cb6d7c128b79f4657895f4b0ba518dd61436140f20d40224baac3a602da83cb254a7e0
+    3f052c63c1f3f00f
+    ""
+    301cc944a1789133bb8048f07dc123f2ca7e20c83988e4bf
+    8be72ebd52cb194d6b0e4fc423bb898f655d938d11985432
+    0564db4049183242;
+  ea6d561ab5aea542db544a14376d5d52f7265c7a8d2fc4feef99b9dba89eb472f71d8eb5affe900d776e4cf74e52b6c86db981143082735c6473a86a5da3d2e8cbb8602ebbaf08bf9315fba15f
+    46714bfd2c8312fb
+    5744dfe84615ddb93f15360161f2efb1fc39b8b6ad97427d
+    caa0435bee7f3a5c11fd01b9c120aa6004f84bcba838a1c3
+    49ac4c21db7bcf9453e935aadb85d304afe6fa4bb10002a0
+    9a90ed7bab6f9d86;
+  3beb4087719135b355dce9ffd6fd639f192e4c2c9a2752bf74a3f63408d3b27df51f44ed5537bfb0162f05edbad1b2c36ceec1dc407475b8e05fcb5ee66c7205f21804c3b73451dc9a3aed7667
+    c6342c8355ff66b9
+    ""
+    1eeffa115cf118eef301f2c93fda303878f7987116dba62d93a7da7027
+    a3c938b621c4032adbd7b5bfeedff1eaa471ddefb2f396290902c00d59
+    d682d2ff660fa862;
+  4ffe5a6506e4e1439de76cc9d332ab03510df3c7d35dc526b5b7785400f53d34b5d55fcac5fbeadd81456bbe6bcedb015be40bfbda656483b32fc4d0a9dc2d7a68b134919d79de5268d7d2ce37
+    2a8a386aa718d09e
+    19612f3d10fe569863bbd3ad42903905058b93
+    4eb213aa037de4e26cd4ceff7490353b5e7621d67ee3ddfb2584e1e12d
+    c494267b5ee0e2bd32b3c4e93b70ddfef6985a4d8360ed32e45209192f
+    32e85181b5d1d655;
+}
+
+rc5-pmac1 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    ""
+    25f3e24d8ae10215;
+  acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed5415
+    4f
+    f7da3d0334f4ad55;
+  8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a
+    96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b9
+    5d24a4c29b90fa71;
+  7e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a8744
+    98ad0abef8bc4fcb70e27e98ef1f0446b42fb1
+    ca50a7dd104238aa;
+  44d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff677
+    ""
+    dfde25eb32b74a23;
+  8554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d1
+    7d
+    58afcfd1b2ec5cca;
+  4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c
+    3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac8
+    3a50ecc246becae2;
+  61a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cf
+    f206877de69146acc3ab6cf8556b7aa7769459
+    ce6c1f810be61bf6;
+  48d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee475
+    ""
+    497b2f55a33bed03;
+  8a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e
+    0c
+    616706b07020fd1b;
+  536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1
+    a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551c
+    af712aca3c532277;
+  a4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb2384
+    1da1ae8f4ae480cda98ad6cf2bacf6f9fd3f82
+    d47974ebfc5228ef;
+  1330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f1
+    ""
+    ee84e75847026484;
+  6f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59c
+    c7
+    5605efcbb6e07489;
+  83443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae648
+    25ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099
+    6182d51653af224a;
+  f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8
+    e9002926ad0284c738f4cb0f58a1e34c8b15ad
+    27da50a416aca31c;
+}
+
+rc5-ocb3 {
+  60d7bcda163547d348b7551195e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    acc87638f508
+    ""
+    ""
+    ""
+    063c1bf330553d8c;
+  046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03
+    d4de16001578
+    46
+    ""
+    ""
+    b6a770d618bfc1d7;
+  b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09
+    c063c46f88de
+    ""
+    9f
+    74
+    570a5073b8afc17f;
+  d41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca9
+    86981a
+    ""
+    874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b
+    fa80154a33c295155643798240fd22d30613b2b6770a3327
+    31aca92d9606f720;
+  6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc
+    69f6a9f2c0
+    945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a125
+    8b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554ac
+    afeb6335d22d91e6027e219981fa6d22fa23d4170ee22c35
+    09e60a6bdcc1ba7f;
+  f1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107
+    c8e7d715a92a
+    ""
+    dd9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5
+    f29328c6d4104e0e1ef80cd7494957aad54f69ae2d1b95e1421c03f769
+    7d433a869031bf7e;
+  afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740d
+    a967828e3604
+    b35b15ffaa6c36800d9645563a308ba6007681
+    7523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a833
+    d403996de8929a47a908bee11ffacc01a85f3d7af8c78ec0094a83e2ea
+    10a662f856acdb4a;
+  1f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959
+    b74dc23a7bb4
+    ""
+    ""
+    ""
+    4fa9e8d71758235e;
+  0e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d3
+    1f06a1dd5982
+    cb
+    ""
+    ""
+    bba7bb90cb237373;
+  c0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b
+    1419ea51cf85
+    ""
+    8f
+    fe
+    e5476d3424c2d40f;
+  938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088
+    e4097e
+    ""
+    fb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba
+    828b48b63905d7d298cf4f88d099cc209fe7483985517503
+    6bd18f02c7a6c90e;
+  61339d6d907eab7707ca48ff5ba1ae93d16225d469de5747bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd651477cd726d6f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a8733b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad09
+    a5b8fa687e
+    c3bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd8
+    4aed8aaebabb7e0f24edfd9710b7bca91b612ea37fc5cc09
+    0089fb21527fed153e81acdc9229d8341ca36df6ebdada9b
+    cc5b59ffe07eaff8;
+  f7f62f66b423fcd2dec5de24d264f2c839839c1b06319f687dbc68d9f07fd41ccb4f8cde8de201ec2680332bbded4883deea0b58b54bdd13c17ef292b0ded3caeb5e57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945d83f923e66b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee78ddd9236beec76d55ed58b
+    10f91d07a037
+    ""
+    791ab96e83c4bf2fb5b205e592c172a5cbc19456c95c1bea6079f3867e
+    0853cf3d4515b9e4b005c95fdddf3c74d4d3ccdaaa1015ae379b550302
+    2a56e4bba5f8d187;
+  52d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f23564672e370ffc37d400a31e8aac1d426ce10df73c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6de738721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d93d1f8fcc53574427767396322b3bf7d02cec05093696cec07591ada462271b1d1519eedde0df37a330fe8c22ebd77705917b7e32ae88f45a34a8ba3037235e19a394be4d26ce47317d8087684456b4cfc5555e925e3e7b2ebc829b2d0505ea617b0ca9531bcdb96040d390
+    40e632d56264
+    3ccb64286303040fcaf679e914eaddc05af884
+    3ce6a427b99a5dc266de31c09165237eeefe4b58cc034b9f099f04678c
+    48d32eec290f067c12f81697153f4030c56b1b79ffe695bc972ffda584
+    15d05287d12f9c8f;
+  2a9da898b39324cd3087a651014f6796f9c4881d89e127e62221e47e57badd678d490c2f320ff8
+    fb1c42761bd4
+    ""
+    ""
+    ""
+    19796de26b769f5b;
+  39f3e96dc0ed1d5b2169912af1a4e2c533c52ba3e8c71c23a089e231480aa63c484fb34bd52239
+    7f102cb8ecf4
+    f6
+    ""
+    ""
+    22f17895a971f1f3;
+  4e329884fe73be257a753b38200bc23f94a079bde2dd98d813655dafa15b85419d15c41a5153cc
+    e5d0e8c8702d
+    ""
+    b2
+    6f
+    511d62bc5b29da6c;
+  ba11927589678d4f7b8fcfad4818c411f15f452300903874f9a532ee46496ae753a2340af7b91f
+    9632fc
+    ""
+    5ae71ae18b40de751ab6b6761ca16434a9935e466e11c1cb
+    a60bb59c8292e00486962cb216e756dd66613fe9569e549d
+    ed2836258e0dfe45;
+  072f32a59c313dba3db646ae909a096697d9a7b0556463ff1126ebc43263391424d02739d0787e
+    804d8f1dcc
+    f6c897a8a48431324324041b5302ccd501b538bd03d5cb5c
+    90d1fd3f7d2be187a787032c79ed900764ee4ce1d3fc042c
+    84e43f8b78a4b759d7832084f4a43b94380155ead68222cf
+    53e98d05afc28fb5;
+  084f7d8c0c48ad7d6f1eabd0fd1ec24a88f26734d5c8d92dbd873a8fe113090d401bea4d28ff49
+    f10ff593adc2
+    ""
+    58e091abd31b62dd1735158f98765970acc6602da063aae01a2a199d3a
+    ccad9333e858aba3b6be61d2821fc6485b94dee4fd3da0f24e18c5c8eb
+    befad9a49693a9ff;
+  4f37a5f062d216d2053a83b5d3a0488ab0d2df631b2892cdfcf9fdd0f37de9ed67179aeae82fe0
+    0009428b297b
+    553230a6d917fa0c1a233c9ebc8a4cba45b205
+    43c540fc1b9dbce078b87a1534acf03897b95a3f372e9f6c5a5f2ae44a
+    d4841df4923358d24721e29a4395fd8410f672286fb862f234d7afe446
+    fbca241edc3784af;
+  7dbce9ba43a39089de20de70d0544b5151db0a16e9769e8f2fc12c7f839fab269a0056284a697ffd4113a1cf43b5d5bdce2d86dead83f5a356e9106bedf908db61f1119f9700260ea9379cc723
+    2184d217158f
+    ""
+    ""
+    ""
+    a8dca51e818d1620;
+  ee8ca42e75614739e9007f234fbcd86b0ad8f641a0449b6d9b0f99d1cb4a57a4d6f987feb0ade90aa1d81c4f497b3734be301da3e25fe692629db57311f422f3a1573f9e0553a23e96265e4326
+    fa532d713686
+    3e
+    ""
+    ""
+    22724c59a99e8a28;
+  5b4bc6c99ade3d4eb23cacdf6e42ad8ca13187eba1532920ba31582b3793b05fa65e9f80c5814b91f4d3c581c7b16c46b484859c6d19eebaf124681aa3be9943307fa4ef095ef8e7e50b703dc0
+    420e74227c93
+    ""
+    51
+    cd
+    d31ba86abcc74ed5;
+  366ef8e98e1e24b48aa989dbb8d0f10471ae5428a6012fbe4f5cb2dab2863e574842cc0b3774e00dcfa63b0db1716c7e916a26fc2e198f8db63ab59955989497782f16c5816270ef3fbe4ea22f
+    484ddc
+    ""
+    12ec8f4bdbd6ebdfbafb21fcf5427dbee5f95b53a0b4cb6d
+    377776c7a23f367f4b797164000341b828e9af1528512d7e
+    640622b80de68169;
+  7c128b79f4657895f4b0ba518dd61436140f20d40224baac3a602da83cb254a7e03f052c63c1f3f00f301cc944a1789133bb8048f07dc123f2ca7e20c83988e4bfea6d561ab5aea542db544a14
+    376d5d52f7
+    265c7a8d2fc4feef99b9dba89eb472f71d8eb5affe900d77
+    6e4cf74e52b6c86db981143082735c6473a86a5da3d2e8cb
+    96695b552838f18f1d0cdede1c6e8b7a94686a80d3faafb2
+    1b2ffe9cea3bdd6f;
+  b8602ebbaf08bf9315fba15f46714bfd2c8312fb5744dfe84615ddb93f15360161f2efb1fc39b8b6ad97427dcaa0435bee7f3a5c11fd01b9c120aa6004f84bcba838a1c33beb4087719135b355
+    dce9ffd6fd63
+    ""
+    9f192e4c2c9a2752bf74a3f63408d3b27df51f44ed5537bfb0162f05ed
+    15dacd515d731592ab85c1b5d9f3dbcde30179b31c493a15f6af916588
+    99a03f7a639d9ac1;
+  bad1b2c36ceec1dc407475b8e05fcb5ee66c7205f21804c3b73451dc9a3aed7667c6342c8355ff66b91eeffa115cf118eef301f2c93fda303878f7987116dba62d93a7da70274ffe5a6506e4e1
+    439de76cc9d3
+    32ab03510df3c7d35dc526b5b7785400f53d34
+    b5d55fcac5fbeadd81456bbe6bcedb015be40bfbda656483b32fc4d0a9
+    82df9af04d4792ef8a746a950613ca561e9d1e395b28cd4efb20400d03
+    b866935e219f4573;
+}
+
+rc5-ocb3-mct {
+  56 5d65dacd57c2aa33;
+  52 03beeb48bcdb2c18;
+  48 01d2c1abfdcd3689;
+  44 4fe9063599fc965e;
+  40 02c7d56243840c7c;
+  36 b8835ac12d93de0c;
+  32 c04dd9d0ccbc4df6;
+  28 7d59856e20a6e739;
+  24 8a1db814d18c6c97;
+  20 99060d584b19a39f;
+  16 722f822efb96b14b;
+  12 20c08832fef3cccd;
+  10 3bb20b4bb9ae613f;
+   8 85f66ee439d96c46;
+  56 f81750a75668;
+  52 67fff337eefc;
+  48 53149ad225e2;
+  44 6cf6c8f56720;
+  40 795b55a03080;
+  36 a2aeb71e7493;
+  32 4581768fa39c;
+  28 e03e2ac2d905;
+  24 f0c24fe14ad1;
+  20 ba83f3fe63f0;
+  16 c42c1512c9fe;
+  12 d1934f3572cd;
+  10 badab855071f;
+   8 084797262a89;
+  56 0c1bc6bd;
+  52 805a3d32;
+  48 9252506e;
+  44 f848c865;
+  40 f4a16d1d;
+  36 57b79a09;
+  32 e8b16e4b;
+  28 a6a0961d;
+  24 04dd92bc;
+  20 8ca6413a;
+  16 2b7d2d10;
+  12 87440aab;
+  10 3277a842;
+   8 b84a6c79;
+}
diff --git a/symm/t/rijndael.local b/symm/t/rijndael.local
new file mode 100644 (file)
index 0000000..e9517f1
--- /dev/null
@@ -0,0 +1,1946 @@
+### Local tests for Rijndael.
+
+rijndael-cmac {
+  ## NIST examples.
+
+  2b7e151628aed2a6abf7158809cf4f3c
+    ""
+    bb1d6929e95937287fa37d129b756746;
+  2b7e151628aed2a6abf7158809cf4f3c
+    6bc1bee22e409f96e93d7e117393172a
+    070a16b46b4d4144f79bdd9dd04a287c;
+  2b7e151628aed2a6abf7158809cf4f3c
+    6bc1bee22e409f96e93d7e117393172aae2d8a57
+    7d85449ea6ea19c823a7bf78837dfade;
+  2b7e151628aed2a6abf7158809cf4f3c
+    6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
+    51f0bebf7e3b9d92fc49741779363cfe;
+
+  8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+    ""
+    d17ddf46adaacde531cac483de7a9367;
+  8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+    6bc1bee22e409f96e93d7e117393172a
+    9e99a7bf31e710900662f65e617c5184;
+  8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+    6bc1bee22e409f96e93d7e117393172aae2d8a57
+    3d75c194ed96070444a9fa7ec740ecf8;
+  8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+    6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
+    a1d5df0eed790f794d77589659f39a11;
+
+  603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
+    ""
+    028962f61b7bf89efc6b551f4667d983;
+  603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
+    6bc1bee22e409f96e93d7e117393172a
+    28a7023f452e8f82bd4bf28d8c37c35c;
+  603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
+    6bc1bee22e409f96e93d7e117393172aae2d8a57
+    156727dc0878944a023c1fe03bad6d93;
+  603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
+    6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
+    e1992190549f6ed5696a2c056c315410;
+
+  ## Locally generated tests.
+  60d7bcda163547d348b7551195e77022
+    ""
+    63f719651118fd4d45cb4feebc3150cb;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    bc9d9dfba6e312cfe8e6c500a1d805d3;
+  8f86edd1dc9268eeee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77
+    ba66e97ee7b233119abc32fa42be9401;
+  bf79192a5b50ade5d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21
+    a51011f5c5d190016cf3e9db6fb32fbc;
+  635c6d62c9269029df3e6057acc87638f5080467
+    ""
+    9285e3dc234cbd47605641edd2052999;
+  33d9ff61cdbda3b3e9878731ebfedd4705e505da
+    14
+    edc6f130780024d1b8b18361790d949c;
+  35dceaa7b1cc49ae1d50c38201a894476b3f102b
+    752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3
+    ac7f798e3227ecb5e4d868c6f07ce3d0;
+  a4f3ebbbb18ac6c95a97a48030370c33d090c542
+    15abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829
+    9045fe42a3307e0d86fa17dbaa73196b;
+  b94586306fed54154f8f28523c03d4de1600157846b710ee72807a22
+    ""
+    b74dbdd96ca8714c2223ce172d7c5541;
+  19bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d
+    42
+    bcbf74240e12721322ac24676c8eeb16;
+  f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e
+    533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5c
+    1889506d1415435dbc580f7b05c1c2e4;
+  fb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc81517
+    84873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6
+    ccf79bcc9696a3887f23f791aa3fbafa;
+  eabdff3bcd211499268878db
+    ""
+    72c93457d9e50f9ce47227ce159722c7;
+  f30f1dad89d4b9b12012e471
+    3d
+    63c431d9cc49118b4af79b5dbf2efded;
+  f46795630e7952d22bb02d71
+    00b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da0
+    86b6a12fb898bf6a4cad2052a70864ad;
+  8da3aefc5f8584b7c5e61766
+    9c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb6
+    3a2d6cd3d65ba29059613d7e6b6e1278;
+}
+
+rijndael-ccm {
+  ## From the Housley, Whiting, and Ferguson submission to NIST, somewhat
+  ## rearranged because of the bizarre (and undocumented) nonce structure.
+
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    00000003020100a0a1a2a3a4a5
+    0001020304050607
+    08090a0b0c0d0e0f101112131415161718191a1b1c1d1e
+    588c979a61c663d2f066d0c2c0f989806d5f6b61dac384
+    17e8d12cfdf926e0;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    00000004030201a0a1a2a3a4a5
+    0001020304050607
+    08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    72c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3b
+    a091d56e10400916;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    00000005040302a0a1a2a3a4a5
+    0001020304050607
+    08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20
+    51b1e5f44a197d1da46b0f8e2d282ae871e838bb64da859657
+    4adaa76fbd9fb0c5;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    00000006050403a0a1a2a3a4a5
+    000102030405060708090a0b
+    0c0d0e0f101112131415161718191a1b1c1d1e
+    a28c6865939a9a79faaa5c4c2a9d4a91cdac8c
+    96c861b9c9e61ef1;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    00000007060504a0a1a2a3a4a5
+    000102030405060708090a0b
+    0c0d0e0f101112131415161718191a1b1c1d1e1f
+    dcf1fb7b5d9e23fb9d4e131253658ad86ebdca3e
+    51e83f077d9c2d93;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    00000008070605a0a1a2a3a4a5
+    000102030405060708090a0b
+    0c0d0e0f101112131415161718191a1b1c1d1e1f20
+    6fc1b011f006568b5171a42d953d469b2570a4bd87
+    405a0443ac91cb94;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    00000009080706a0a1a2a3a4a5
+    0001020304050607
+    08090a0b0c0d0e0f101112131415161718191a1b1c1d1e
+    0135d1b2c95f41d5d1d4fec185d166b8094e999dfed96c
+    048c56602c97acbb7490;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    0000000a090807a0a1a2a3a4a5
+    0001020304050607
+    08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    7b75399ac0831dd2f0bbd75879a2fd8f6cae6b6cd9b7db24
+    c17b4433f434963f34b4;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    0000000b0a0908a0a1a2a3a4a5
+    0001020304050607
+    08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20
+    82531a60cc24945a4b8279181ab5c84df21ce7f9b73f42e197
+    ea9c07e56b5eb17e5f4e;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    0000000c0b0a09a0a1a2a3a4a5
+    000102030405060708090a0b
+    0c0d0e0f101112131415161718191a1b1c1d1e
+    07342594157785152b074098330abb141b947b
+    566aa9406b4d999988dd;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    0000000d0c0b0aa0a1a2a3a4a5
+    000102030405060708090a0b
+    0c0d0e0f101112131415161718191a1b1c1d1e1f
+    676bb20380b0e301e8ab79590a396da78b834934
+    f53aa2e9107a8b6c022c;
+  c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+    0000000e0d0c0ba0a1a2a3a4a5
+    000102030405060708090a0b
+    0c0d0e0f101112131415161718191a1b1c1d1e1f20
+    c0ffa0d6f05bdb67f24d43a4338d2aa4bed7b20e43
+    cd1aa31662e7ad65d6db;
+  aca23752615c82c1d454c4fc1462dcf3
+    00b9965d963ec163c54530549a
+    20f2c84a078983d6
+    d9215a08e37911f08e13e868d561fd8de3bc968e0978ae
+    8ca7df83589d89f1e2f9633a4e219e4e8c4daf918cbd4a
+    795fa85da6e5711c;
+  aca23752615c82c1d454c4fc1462dcf3
+    0044144a825d7363c54530549a
+    23bc9db76f5e4761
+    5297b4a9984845b03b01cf4794fa66cf27cc89c002ff4a4b
+    c7d563f1e02eb4f54919ae707d6cc9573ca85434f3559b30
+    78aeda0f601d877e;
+  aca23752615c82c1d454c4fc1462dcf3
+    00aaf7bf9d75c663c54530549a
+    86eec4ba8409465f
+    875547667e2424abb2a30fde33b6e81c2b5c1c5629b262555c
+    a15c03b3d37d1f5fba858d394997e935c44985212cfaed5037
+    bd7dd7a68f95a476;
+  aca23752615c82c1d454c4fc1462dcf3
+    0040da4cf416fc63c54530549a
+    15801a12adb41e13223d9c4f
+    f1d25ee5bd3014d5eb7254c3c62ded9d1dbb7d
+    0c9c100d74193c6d5679cd01b6418fff3a4fe4
+    7cf0866237842658;
+  aca23752615c82c1d454c4fc1462dcf3
+    002c2cbdfa28bf63c54530549a
+    d9808ff2b59b6a89bf9c4a82
+    05bba8822b40f4803253fb91f0b5bcf60ee5dd95
+    b5b3b7fab03d662e1842333328466dd81dd8fe3d
+    6f8c861ab1617dc3;
+  aca23752615c82c1d454c4fc1462dcf3
+    0016230909f7cc63c54530549a
+    9b85df31226b387fdf8ddd4d
+    4eb993044b71beddc6ef3f287197e4d46e9f29e427
+    a0e19481ba549ce66fadd81937a09a4f542b2f421d
+    12695462fd931591;
+  aca23752615c82c1d454c4fc1462dcf3
+    00797b71e3c96963c54530549a
+    e7e6473a07dacca4
+    9436254b379e38d73861ca027fc79b0440aba519e9e1dc
+    0d22d68dc1d39934f8e5882c2058436a0cc58e03258b4e
+    2bb39e01a568aba1f1ba;
+  aca23752615c82c1d454c4fc1462dcf3
+    0083ae22deb9b163c54530549a
+    a1c6b900678806b8
+    37709803b3fff94ffac1150b28a3cef1bf4feea0ff19541c
+    3103c511e43dc5e01aba07db0b84a443a1e3425983c3fe7e
+    19c626fd947eafb9c1b3;
+  aca23752615c82c1d454c4fc1462dcf3
+    006541e08f013463c54530549a
+    ea6abbb54793ecc2
+    eb0e990f88cfb0e78c1d6196890f8b6fa7787fe2dd85a72355
+    a449f8b7a3c9d0c3fca9a6e7a89953fdbbb5d4d05dc77f67ae
+    4efbc470d8a0b1c4f967;
+  aca23752615c82c1d454c4fc1462dcf3
+    00ede32aa3875a63c54530549a
+    869cbaf565fbb429d4603ace
+    6cd5e33d9e5ff526e21b24f40d6b15e5ed25fb
+    450c728aac9be3105cbe74653ffd52feb4a5ad
+    d6db7bc4dfdfc165dd93;
+  aca23752615c82c1d454c4fc1462dcf3
+    0073331529b3db63c54530549a
+    934cae407d3e300ae7111b43
+    e9a5e8b187d1e7baa3ad94fcf9e1b25aff726259
+    5f7716b16a6218b2a44033c29260df1d75caadd4
+    583c50b41845b3867f21;
+  aca23752615c82c1d454c4fc1462dcf3
+    00cdf8f729be7363c54530549a
+    6dbf3223e9758ce37ed8e2a9
+    ab8db40bc61588976d79d96e3012f0ff60e37e0732
+    220bb8f4aba55c7d573f1f2fbd3d78a4361c665f51
+    659f6d2e866db4de0e97;
+
+  ## From NIST SP800-38C.
+  404142434445464748494a4b4c4d4e4f
+    10111213141516
+    0001020304050607
+    20212223
+    7162015b
+    4dac255d;
+  404142434445464748494a4b4c4d4e4f
+    1011121314151617
+    000102030405060708090a0b0c0d0e0f
+    202122232425262728292a2b2c2d2e2f
+    d2a1f0e051ea5f62081a7792073d593d
+    1fc64fbfaccd;
+  404142434445464748494a4b4c4d4e4f
+    101112131415161718191a1b
+    000102030405060708090a0b0c0d0e0f10111213
+    202122232425262728292a2b2c2d2e2f3031323334353637
+    e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5
+    484392fbc1b09951;
+
+  ## Other NIST examples.
+  404142434445464748494a4b4c4d4e4f
+    10111213141516
+    ""
+    202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    7162015bc051951e5918aeaf3c11f3d4ac363f8d5b6af3d369603b04f24cae29964e2f2bf9d31143f72527ce2db402eab7660e4a10b08e82266517cdf60267f9
+    c66b655c;
+  404142434445464748494A4B4C4D4E4F
+    10111213141516
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+    ""
+    ""
+    e84023f8;
+  404142434445464748494a4b4c4d4e4f5051525354555657
+    10111213141516
+    0001020304050607
+    20212223
+    18ee1730
+    c8c326d5;
+  404142434445464748494a4b4c4d4e4f5051525354555657
+    1011121314151617
+    000102030405060708090a0b0c0d0e0f
+    202122232425262728292a2b2c2d2e2f
+    2232b6e0924148ae7239bcbd1a0f7ecb
+    56e9cc28aa67;
+  404142434445464748494a4b4c4d4e4f5051525354555657
+    101112131415161718191a1b
+    000102030405060708090a0b0c0d0e0f10111213
+    202122232425262728292a2b2c2d2e2f3031323334353637
+    8081316fd89624d62ce7637fb94995b6631c50d61586de01
+    42366952505f995a;
+  404142434445464748494a4b4c4d4e4f5051525354555657
+    10111213141516
+    ""
+    202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    18ee1730f4490ea847a8e9c532c69f9c0a539a585c1e7b6a5af919f4819088a96ed632555098d3007e7d963c7bd013eb307671d0fbc39a0df4a26a9f4b9e4dad
+    c9ce2fbc;
+  404142434445464748494a4b4c4d4e4f5051525354555657
+    10111213141516
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+    ""
+    ""
+    f1fb2a57;
+  404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    10111213141516
+    0001020304050607
+    20212223
+    8ab1a874
+    95fc0820;
+
+  404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    1011121314151617
+    000102030405060708090a0b0c0d0e0f
+    202122232425262728292a2b2c2d2e2f
+    af1785fc0f5ea7d0cfba837246484497
+    94b826c8849e;
+
+  404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    101112131415161718191a1b
+    000102030405060708090a0b0c0d0e0f10111213
+    202122232425262728292a2b2c2d2e2f3031323334353637
+    04f883aeb3bd0730eaf50bb6de4fa2212034e4e41b0e75e5
+    2b48c8766f7e7649;
+
+  404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    10111213141516
+    ""
+    202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    8ab1a874f6853f2443a59500f78d17272d6d39dfa6d0e65107b10700c2ce9ee8663d3e2a01c2e12c32e9377442231920be53278f4f60a972b709bb16932936ba
+    3fbd0fae;
+
+  404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+    10111213141516
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+    ""
+    ""
+    a6cf8230;
+
+  ## Locally generated tests.
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26
+    ""
+    ""
+    ""
+    cf28ba78;
+  d0c6eb14ad568f86edd1dc9268eeee53
+    3285a6ed810c9b689daaa9
+    06
+    ""
+    ""
+    f258e4d7;
+  0d2d4b6003062365b0a54364c76c160f
+    11896c4794846ecfa14a71
+    ""
+    30
+    d6
+    0c31647b;
+  c9f137120634c9519848a877ff77bf79
+    192a5b50ade5d9cd73
+    9a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21
+    635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49
+    41b97c9616d0af69288f13e20d74901645bc9b5263044121e5562fa5b0e5ef40a2639909c2e07e329cc50737613a2c53
+    e992acc597653980b46bc43fd471eb5f;
+  ae1d50c38201a894476b3f102b752eb9
+    529533966f27043eb6
+    21b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6
+    c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3
+    8c314091d48b18dba473f0180ebfa878c920562f0d3c63303cafd8b92e31c35ca8e30e5dde711d30e7360b70030864de8d8156be5e
+    672d9df3a0e99ed948e4f598a913b421;
+  349829b94586306fed54154f8f28523c03d4de16
+    00157846b710ee72807a22
+    ""
+    ""
+    ""
+    9205b2da;
+  19bfb474fd71d891f24bb65d1563259f9eb53b57
+    1ea629c54d57dd2d42f708
+    00
+    ""
+    ""
+    9ae9b8a9;
+  df9fcbaca48b77dba189196d1ebba10b0467cb9f
+    c2712a199e533fa9156308
+    ""
+    cd
+    19
+    fab4799d;
+  ec3f768281e040a9b9a222bd689aef66f5306ceb
+    0c6b08ac8b0a22260c
+    571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da
+    6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf3
+    a11307a1d9df486ff782f6643324950ec651e2df47bab6ef1254fa7d04b59bca5f509bc9e781ed797105d39fb509de45
+    27d12d4fb2bc29dc306d5c2240e4894c;
+  0f1dad89d4b9b12012e4713df46795630e7952d2
+    2bb02d7100b8b64937
+    7d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da0
+    8da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7ca
+    45adc79632d8fdc8470e9ea47e2523d2a9ad568b2817b5295c078756df3d7f584aaf4b4e9667023b719c1ef7ad9cb72bdf31746f56
+    f1855db5745f0561fd8113b2ff6006ce;
+  dcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498
+    ad0abef8bc4fcb70e27e98
+    ""
+    ""
+    ""
+    a84a331d;
+  ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4
+    ae985511265febd11c1647
+    20
+    ""
+    ""
+    e4256cb2;
+  eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0c
+    fa9138ddc39908445608fe
+    ""
+    95
+    52
+    87c71b52;
+  e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3
+    f9099c5ffb824173d7
+    634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc
+    9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911
+    b000328931c8a1484cae26f4f7be0415d58858fcff326136d37fd981492c5851163f68326cac9d4b80f29f5c157a28c2
+    9b9c5705e2d569fc1b280731e4286027;
+  e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c9
+    67c0a458cb948bdd40
+    9b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8de
+    b9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb4
+    d038ac6646cb2b6da23963eac488def0a233d63e097f9b981d322f96d6cad2d2c2be978d566a5afd8b20ecff4f1c8765ee5446c2a3
+    28b572f708c9a6eb036444c0a9e8818c;
+  4d65bad397abfaf529ee41cf
+    9a05c7efedef3401539c51
+    ""
+    ""
+    ""
+    66c301e7;
+  d2a90bbf7f1bfc338ab0ef57
+    46ea8fdcccd213e33f7e8a
+    57
+    ""
+    ""
+    df5a4e4e;
+  18fd25014107c8e7d715a92a
+    dd9589d1f5c054b2d98351
+    ""
+    46
+    2a
+    0c3bbfb2;
+  05ec590294a319b9802068a9
+    f891bc5ba5afabf8c3
+    122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde9
+    5759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4
+    5c4a984366df29ee88817bba556a52b0c17ce5c3a337caac667c792cd1d7b705e3db87734963b51d606d8022346fc267
+    1494a9ba0a649a71409b719d821d546f;
+  563d405e51881e99027b8ab9
+    aea3ccf860b0009740
+    763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3
+    aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd6777
+    73f618f0bfb917a6ca4f6b7872dbd148fa97bbf8ab044f3331410eef1be00037e9293d851e99ee70c65cad306c4fc0cee754ee1e5c
+    f1c35f66bbb6b69b6c7aa3e7ed23e47e;
+}
+
+rijndael-eax {
+  ## From Mihir Bellare, Phillip Rogaway, David Wagner, `The EAX Mode of
+  ## Operation (A Two-Pass Authenticated-Encryption Scheme Optimized for
+  ## Simplicity and Efficiency)'.
+
+  233952dee4d5ed5f9b9c6d6ff80ff478
+    62ec67f9c3a4a407fcb2a8c49031a8b3
+    6bfb914fd07eae6b
+    ""
+    ""
+    e037830e8389f27b025a2d6527e79d01;
+  91945d3f4dcbee0bf45ef52255f095a4
+    becaf043b0a23d843194ba972c66debd
+    fa3bfd4806eb53fa
+    f7fb
+    19dd
+    5c4c9331049d0bdab0277408f67967e5;
+  01f74ad64077f2e704c0f60ada3dd523
+    70c3db4f0d26368400a10ed05d2bff5e
+    234a3463c1264ac6
+    1a47cb4933
+    d851d5bae0
+    3a59f238a23e39199dc9266626c40f80;
+  d07cf6cbb7f313bdde66b727afd3c5e8
+    8408dfff3c1a2b1292dc199e46b7d617
+    33cce2eabff5a79d
+    481c9e39b1
+    632a9d131a
+    d4c168a4225d8e1ff755939974a7bede;
+  35b6d0580005bbc12b0587124557d2c2
+    fdb6b06676eedc5c61d74276e1f8e816
+    aeb96eaebe2970e9
+    40d0c07da5e4
+    071dfe16c675
+    cb0677e536f73afe6a14b74ee49844dd;
+  bd8e6e11475e60b268784c38c62feb22
+    6eac5c93072d8e8513f750935e46da1b
+    d4482d1ca78dce0f
+    4de3b35c3fc039245bd1fb7d
+    835bb4f15d743e350e728414
+    abb8644fd6ccb86947c5e10590210a4f;
+  7c77d6e813bed5ac98baa417477a2e7d
+    1a8c98dcd73d38393b2bf1569deefc19
+    65d2017990d62528
+    8b0a79306c9ce7ed99dae4f87f8dd61636
+    02083e3979da014812f59f11d52630da30
+    137327d10649b0aa6e1c181db617d7f2;
+  5fff20cafab119ca2fc73549e20f5b0d
+    dde59b97d722156d4d9aff2bc7559826
+    54b9f04e6a09189a
+    1bda122bce8a8dbaf1877d962b8592dd2d56
+    2ec47b2c4954a489afc7ba4897edcdae8cc3
+    3b60450599bd02c96382902aef7f832a;
+  a4a4782bcffd3ec5e7ef6d8c34a56123
+    b781fcf2f75fa5a8de97a9ca48e522ec
+    899a175897561d7e
+    6cf36720872b8513f6eab1a8a44438d5ef11
+    0de18fd0fdd91e7af19f1d8ee8733938b1e8
+    e7f6d2231618102fdb7fe55ff1991700;
+  8395fcf1e95bebd697bd010bc766aac3
+    22e7add93cfc6393c57ec0b3c17d6b44
+    126735fcc320d25a
+    ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7
+    cb8920f87a6c75cff39627b56e3ed197c552d295a7
+    cfc46afc253b4652b1af3795b124ab6e;
+
+  ## Some local tests for additional edge cases, generated using the toy
+  ## implementation in Python.
+  60d7bcda163547d348b7551195e77022
+    ""
+    ""
+    ""
+    ""
+    fc65784451ea97468ec025e17a709456;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    ""
+    ""
+    ""
+    d8da3364e510165ed5afd2aab762f5d2;
+  8f86edd1dc9268eeee533285a6ed810c
+    ""
+    9b
+    ""
+    ""
+    715b06133d886f3b8fb8fdfcadd0fa5c;
+  689daaa9060d2d4b6003062365b0a543
+    ""
+    ""
+    64
+    69
+    16c192d8633a39465ce18da2ce132233;
+  c76c160f11896c4794846ecfa14a7130
+    c9f137120634c9519848a877ff77bf79
+    192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8
+    cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505
+    963801ede08bd2b86a3c33cf18c27d98c7c22f14c08621651e6094e72bcbd4bbf38f5e20814d465daa9c5929b9f59375
+    180ad55fa758703dd6a4e345956705e5;
+  da1435dceaa7b1cc49ae1d50c38201a8
+    94476b3f102b752eb9529533966f27
+    043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac
+    448792431ef5eb64efcfb2e6a9bb454d7ef09598ca4bc057d9cba969328ad75c05b7da7012e5ff1826dc3c981072fc9dce719cfffa
+    aeaa46b633b5c3ba7db2e404af2eb9a8;
+  26afa3349829b94586306fed54154f8f28523c03
+    ""
+    ""
+    ""
+    ""
+    d0a749a3ae472501971c7521066a5c14;
+  d4de1600157846b710ee72807a2219bfb474fd71
+    d8
+    ""
+    ""
+    ""
+    5998cfaef8d97abd4c8017aba424a845;
+  91f24bb65d1563259f9eb53b571ea629c54d57dd
+    ""
+    2d
+    ""
+    ""
+    7ecfd7cde12120a79d65622bd02993f8;
+  42f70800df9fcbaca48b77dba189196d1ebba10b
+    ""
+    ""
+    04
+    46
+    b4b2f22374e5416565ea5da09bd65726;
+  67cb9fc2712a199e533fa9156308cdec3f768281
+    e040a9b9a222bd689aef66f5306ceb0c
+    6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc81517
+    84873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd
+    78ebdb6a281df84204a58c3071a81ee62c604c4ff408d02ec9401bd284beba033e438279a8cf450bccc58ddb0480b0b1
+    8f3edaf96c1c577c99d506fa9bdd342c;
+  211499268878dbf30f1dad89d4b9b12012e4713d
+    f46795630e7952d22bb02d7100b8b6
+    49377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d079839180
+    5da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0
+    b81e04dfef276af4992a4daacad70a724bd2bc5f857d739b82781dab188f6c172f1dc3390ab9226f6a286bf89e3fd198ee3e781db4
+    1096e8cbf9132840e22c4e9618a981c2;
+  b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a87
+    ""
+    ""
+    ""
+    ""
+    8517441bde0b33302a5d73d756bbaea3;
+  4498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc1
+    88
+    ""
+    ""
+    ""
+    2703e5e0acbf6d762e635e66e599c7e7;
+  d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c
+    ""
+    8d
+    ""
+    ""
+    21ba7e9152f7a188a570a435a9118dd7;
+  d0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc3
+    ""
+    ""
+    99
+    8f
+    19edae1a9f72c3ec1a95456a7602fbea;
+  08445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b8
+    07e6daa089c3f9099c5ffb824173d763
+    4c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9b
+    c597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e3
+    7da2cbb1dbb96d57e6eae7f7463cdaf220f06e96bcce1303ef6c987de22fa64d62c89f8bef1676b6c9447b03575fce9a
+    83e41c3c033397193406be50be532022;
+  2d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967
+    c0a458cb948bdd409b687fa3a6827b
+    480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c
+    091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfa
+    5c26f8ce44729fef7b23d7a08a6f770499d3efd779ec6975b549f418abdffc8a1fe5c279e41e3815b8667e96a4ad39aeef24bee42f
+    cd68c88ece3bead81778b31e8dbe34db;
+  f529ee41cf9a05c7efedef34
+    ""
+    ""
+    ""
+    ""
+    9fa09ea950f21cf235e494490111462f;
+  01539c51d2a90bbf7f1bfc33
+    8a
+    ""
+    ""
+    ""
+    b694f1a079840c1a5306fa86a0d4bba3;
+  b0ef5746ea8fdcccd213e33f
+    ""
+    7e
+    ""
+    ""
+    91c2e974c399c84bdff77b962441e1f3;
+  8a5718fd25014107c8e7d715
+    ""
+    ""
+    a9
+    14
+    279ad0e41ab70a6751f9fbd01030784e;
+  2add9589d1f5c054b2d98351
+    4605ec590294a319b9802068a9f891bc
+    5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725c
+    b2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d9803
+    cb3a052da8d3fc8c6e40de726ef40596a871d596df7b7c33b11467ba4ab39210df119a6e202267b44f86db3b4074c886
+    4ea05695bbf7f261c4e76415e3642945;
+  98bd94e66eb4563d405e5188
+    1e99027b8ab9aea3ccf860b0009740
+    763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3
+    aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd6777
+    03f7e555335edc0f776c210da68ddceda30e7b6d11f62aab60a17f443e6000c31ca8927b28791f8b5dcff245c82b63ebca8cdbeb9a
+    a860ca21635e5d2c1fa19d96a4c394fa;
+}
+
+rijndael-gcm {
+
+  ## NIST examples.
+  feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    ""
+    ""
+    ""
+    3247184b3c4f69a44dbcd22887bbb418;
+  feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    ""
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+    42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985
+    4d5c2af327cd64a62cf35abd2ba6fab4;
+  feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4
+    ""
+    ""
+    5f91d77123ef5eb9997913849b8dc1e9;
+  feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+    42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985
+    64c0232904af398a5b67c10b53a5024d;
+  feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d585
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091
+    f07c2528eea2fca1211f905e1b6a881b;
+
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    cafebabefacedbaddecaf888
+    ""
+    ""
+    ""
+    c835aa88aebbc94f5a02e179fdcfc3e4;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    cafebabefacedbaddecaf888
+    ""
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+    3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256
+    9924a7c8587336bfb118024db8674a14;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4
+    ""
+    ""
+    02cc773bc919f4e1c5e9c54313bface0;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+    3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256
+    3b9153b4e7318a5f3bbeac108f8a8edb;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d585
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710
+    93ea28c659e269902a80acd208e7fc80;
+
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    ""
+    ""
+    ""
+    fd2caa16a5832e76aa132c1453eeda7e;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    ""
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+    522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
+    b094dac5d93471bdec1a502270e3cc6c;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4
+    ""
+    ""
+    de34b6dcd4cee2fdbec3cea01af1ee44;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+    522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
+    c06d76f31930fef37acae23ed465ae62;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    3ad77bb40d7a3660a89ecaf32466ef97f5d3d585
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662
+    e097195f4532da895fb917a5a55c6aa0;
+
+  ## IEEE tests for P802.1.
+  ad7a2bd03eac835a6f620fdcb506b345
+    12153524c0895e81b2c28465
+    d609b1f056637a0d46df998d88e5222ab2c2846512153524c0895e8108000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233340001
+    ""
+    ""
+    f09478a9b09007d06f46e9b6a1da25dd;
+  ad7a2bd03eac835a6f620fdcb506b345
+    12153524c0895e81b2c28465
+    d609b1f056637a0d46df998d88e52e00b2c2846512153524c0895e81
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a0002
+    701afa1cc039c0d765128a665dab69243899bf7318ccdc81c9931da17fbe8edd7d17cb8b4c26fc81e3284f2b7fba713d
+    4f8d55e7d3f06fd5a13c0c29b9d5b880;
+  071b113b0ca743fecccf3d051f737382
+    f0761e8dcd3d000176d457ed
+    e20106d7cd0df0761e8dcd3d88e5400076d457ed08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a0003
+    ""
+    ""
+    0c017bc73b227dfcc9bafa1c41acc353;
+  071b113b0ca743fecccf3d051f737382
+    f0761e8dcd3d000176d457ed
+    e20106d7cd0df0761e8dcd3d88e54c2a76d457ed
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233340004
+    13b4c72b389dc5018e72a171dd85a5d3752274d3a019fbcaed09a425cd9b2e1c9b72eee7c9de7d52b3f3
+    d6a5284f4a6d3fe22a5d6c2b960494c3;
+  013fe00b5f11be7f866d0cbbc55a7a90
+    7cfde9f9e33724c68932d612
+    84c5d513d2aaf6e5bbd2727788e523008932d6127cfde9f9e33724c608000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f0005
+    ""
+    ""
+    217867e50c2dad74c28c3b50abdf695a;
+  013fe00b5f11be7f866d0cbbc55a7a90
+    7cfde9f9e33724c68932d612
+    84c5d513d2aaf6e5bbd2727788e52f008932d6127cfde9f9e33724c6
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b0006
+    3a4de6fa32191014dbb303d92ee3a9e8a1b599c14d22fb080096e13811816a3c9c9bcf7c1b9b96da809204e29d0e2a7642
+    bfd310a4837c816ccfa5ac23ab003988;
+  88ee087fd95da9fbf6725aa9d757b0cd
+    7ae8e2ca4ec500012e58495c
+    68f2e77696ce7ae8e2ca4ec588e541002e58495c08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d0007
+    ""
+    ""
+    07922b8ebcf10bb2297588ca4c614523;
+  88ee087fd95da9fbf6725aa9d757b0cd
+    7ae8e2ca4ec500012e58495c
+    68f2e77696ce7ae8e2ca4ec588e54d002e58495c
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748490008
+    c31f53d99e5687f7365119b832d2aae70741d593f1f9e2ab3455779b078eb8feacdfec1f8e3e5277f8180b43361f6512adb16d2e38548a2c719dba7228d840
+    88f8757adb8aa788d8f65ad668be70e7;
+
+  e3c08a8f06c6e3ad95a70557b23f75483ce33021a9c72b7025666204c69c0b72
+    12153524c0895e81b2c28465
+    d609b1f056637a0d46df998d88e5222ab2c2846512153524c0895e8108000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233340001
+    ""
+    ""
+    2f0bc5af409e06d609ea8b7d0fa5ea50;
+  e3c08a8f06c6e3ad95a70557b23f75483ce33021a9c72b7025666204c69c0b72
+    12153524c0895e81b2c28465
+    d609b1f056637a0d46df998d88e52e00b2c2846512153524c0895e81
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a0002
+    e2006eb42f5277022d9b19925bc419d7a592666c925fe2ef718eb4e308efeaa7c5273b394118860a5be2a97f56ab7836
+    5ca597cdbb3edb8d1a1151ea0af7b436;
+  691d3ee909d7f54167fd1ca0b5d769081f2bde1aee655fdbab80bd5295ae6be7
+    f0761e8dcd3d000176d457ed
+    e20106d7cd0df0761e8dcd3d88e5400076d457ed08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a0003
+    ""
+    ""
+    35217c774bbc31b63166bcf9d4abed07;
+  691d3ee909d7f54167fd1ca0b5d769081f2bde1aee655fdbab80bd5295ae6be7
+    f0761e8dcd3d000176d457ed
+    e20106d7cd0df0761e8dcd3d88e54c2a76d457ed
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233340004
+    c1623f55730c93533097addad25664966125352b43adacbd61c5ef3ac90b5bee929ce4630ea79f6ce519
+    12af39c2d1fdc2051f8b7b3c9d397ef2;
+  83c093b58de7ffe1c0da926ac43fb3609ac1c80fee1b624497ef942e2f79a823
+    7cfde9f9e33724c68932d612
+    84c5d513d2aaf6e5bbd2727788e523008932d6127cfde9f9e33724c608000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f0005
+    ""
+    ""
+    6ee160e8faeca4b36c86b234920ca975;
+  83c093b58de7ffe1c0da926ac43fb3609ac1c80fee1b624497ef942e2f79a823
+    7cfde9f9e33724c68932d612
+    84c5d513d2aaf6e5bbd2727788e52f008932d6127cfde9f9e33724c6
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b0006
+    110222ff8050cbece66a813ad09a73ed7a9a089c106b959389168ed6e8698ea902eb1277dbec2e68e473155a15a7daeed4
+    a10f4e05139c23df00b3aadc71f0596a;
+  4c973dbc7364621674f8b5b89e5c15511fced9216490fb1c1a2caa0ffe0407e5
+    7ae8e2ca4ec500012e58495c
+    68f2e77696ce7ae8e2ca4ec588e541002e58495c08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d0007
+    ""
+    ""
+    00bda1b7e87608bcbf470f12157f4c07;
+  4c973dbc7364621674f8b5b89e5c15511fced9216490fb1c1a2caa0ffe0407e5
+    7ae8e2ca4ec500012e58495c
+    68f2e77696ce7ae8e2ca4ec588e54d002e58495c
+    08000f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748490008
+    ba8ae31bc506486d6873e4fce460e7dc57591ff00611f31c3834fe1c04ad80b66803afcf5b27e6333fa67c99da47c2f0ced68d531bd741a943cff7a6713bd0
+    2611cd7daa01d61c5c886dc1a8170107;
+
+  ## From `The Galois/Counter Mode of Operation' by David McGrew and John
+  ## Viega.  Some of these were duplicated in the NIST examples above, and so
+  ## are omitted here.
+  00000000000000000000000000000000
+    000000000000000000000000
+    ""
+    ""
+    ""
+    58e2fccefa7e3061367f1d57a4e7455a;
+  00000000000000000000000000000000
+    000000000000000000000000
+    ""
+    00000000000000000000000000000000
+    0388dace60b6a392f328c2b971b2fe78
+    ab6e47d42cec13bdf53a67b21257bddf;
+  feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091
+    5bc94fbc3221a5db94fae95ae7121a47;
+  feffe9928665731c6d6a8f9467308308
+    cafebabefacedbad
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598
+    3612d2e79e3b0785561be14aaca2fccb;
+  feffe9928665731c6d6a8f9467308308
+    9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5
+    619cc5aefffe0bfa462af43c1699d050;
+
+  000000000000000000000000000000000000000000000000
+    000000000000000000000000
+    ""
+    ""
+    ""
+    cd33b28ac773f74ba00ed1f312572435;
+  000000000000000000000000000000000000000000000000
+    000000000000000000000000
+    ""
+    00000000000000000000000000000000
+    98e7247c07f0fe411c267e4384b0f600
+    2ff58d80033927ab8ef4d4587514f0fb;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    cafebabefacedbaddecaf888
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710
+    2519498e80f1478f37ba55bd6d27618c;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    cafebabefacedbad
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7
+    65dcc57fcf623a24094fcca40d3533f8;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c
+    9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b
+    dcf566ff291c25bbb8568fc3d376a6d9;
+
+  0000000000000000000000000000000000000000000000000000000000000000
+    000000000000000000000000
+    ""
+    ""
+    ""
+    530f8afbc74536b9a963b4f1c4cb738b;
+  0000000000000000000000000000000000000000000000000000000000000000
+    000000000000000000000000
+    ""
+    00000000000000000000000000000000
+    cea7403d4d606b6e074ec5d3baf39d18
+    d0d1c8a799996bf0265b98b5d48ab919;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    cafebabefacedbaddecaf888
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662
+    76fc6ece0f4e1768cddf8853bb2d551b;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    cafebabefacedbad
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f
+    3a337dbf46a792c45e454913fe2ea8f2;
+  feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+    9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+    feedfacedeadbeeffeedfacedeadbeefabaddad2
+    d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+    5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f
+    a44a8266ee1c8eb0c8b5d4cf5ae9f19a;
+
+  ## Further home-made tests, made using the toy Python implementation.
+  60d7bcda163547d348b7551195e77022
+    ""
+    ""
+    ""
+    ""
+    58b01ea630bccf61f3b34c172d152383;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    ""
+    ""
+    ""
+    4728c593444566c1f955bbf6b3d38240;
+  8f86edd1dc9268eeee533285a6ed810c
+    ""
+    9b
+    ""
+    ""
+    d13020f394c38a8e22c46ccd91d10d77;
+  689daaa9060d2d4b6003062365b0a543
+    ""
+    ""
+    64
+    bc
+    4daa100a72a49783462b47a93ae6bf16;
+  c76c160f11896c4794846ecfa14a7130
+    c9f137120634c9519848a877ff77bf79
+    192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8
+    cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505
+    382909981d309ca85ad62f43d0ed0d416f8040e3517772510ff95e50d9e411319e636647904a1c7ac2d857ed1996414b
+    06ba36bc635adcbd1854fcef36614528;
+  da1435dceaa7b1cc49ae1d50c38201a8
+    94476b3f102b752eb9529533
+    966f27043eb621b7f65b000961040ef2f9b2fc
+    5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93b
+    7629cb94f9f709fd7c0988e50e935c3f95dc15a4f49207d62b3ba01fe62f0733842b97e72753292de7f4b3d0518ec30933d80bb3c93c5f2165
+    f894c92668f0264a7f663568f38c3d71;
+  f4f2aad2605faee2b03fb648e27fff63
+    102758fe2b69ac26afa3349829b945
+    86306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9e
+    b53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e0
+    08bcec80c6486cc37d15f4da0dd221864d01b6bf9726ea9de673625a80e07e1250da4071099ffc8b50dc5cd1bfaaac50abef3d1b5a
+    9456d186568dd1aca2e61c96d2ae9998;
+  40a9b9a222bd689aef66f5306ceb0c6b08ac8b0a
+    ""
+    ""
+    ""
+    ""
+    d18fdc91e2ace4c8f4d66cf473fb42db;
+  22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95
+    21
+    ""
+    ""
+    ""
+    93bcc629e1dc644f4f002440da2c9cca;
+  4ade49cb3b6f5fe8368131115c037ba323fe1dc8
+    ""
+    15
+    ""
+    ""
+    e87f107bb704c288cc68519cec9fa3d8;
+  1784873f0eb5b647da6794c18b5337685a96ed65
+    ""
+    ""
+    b9
+    c1
+    c59a50c109f521ba596b3bfdff74fe9d;
+  aca338527ef19b09c063c46f88de9fd41e72d7b9
+    7e23e6eabdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa92
+    1451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1
+    8068670d29a2a061b8375eb1e34259255991e9fadde3c5662930c9d29fe66fa5d513bfd6f2201e1503974444c827154b
+    67f81d876969b8f8af546599fb81b929;
+  ecdf3d264a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658
+    b970e47479a684b5aefa69a4cd52147ed12ca9
+    86981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720
+    23d16173096538a850efd193113ce4664d122a0e5ef73a70b50b57304b62704f65b9b1b1167d3e9a3cc66f95b873a856a05de800a91c2d43bc
+    c2a7ef96a5228db104f6a11034e50f8a;
+  eef9eb1c8dd0b00951f284649016ed0045633185
+    4bc78bf43966eb0cfa9138ddc39908
+    445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d763
+    4c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccb
+    9ef6b1732748b5f4fee62e025d4fa736336574ede8e760c680d546ecd9c51a03b3bfea4f3eff602cacdf9822717325ffff92196aa2
+    1279f19bf183b1499da8da81e174d2b8;
+  b2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4f
+    ""
+    ""
+    ""
+    ""
+    565ff4cb468ce9c2c53451df7cc70651;
+  fa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6
+    77
+    ""
+    ""
+    ""
+    e5f4f21a54e3788920c3fda8e47a561a;
+  8554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a682
+    ""
+    7b
+    ""
+    ""
+    fea5e7d3d32a547d19d029133e417f4c;
+  480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8
+    ""
+    ""
+    74
+    2c
+    a0b8a9979dfb02faac0cfd7798f31e6f;
+  3d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b085
+    1e5ca605ac8451399587011677508a15
+    dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338a
+    b0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b980
+    c5c15ee7953a0b74712d9cfe36c7270a94c265f1af75b48e9147b54bf3509bea55e58c6ef3d7e60db1270d6f5f56d37b
+    94d5625b8c1c2dc0eb7914e717dd640f;
+  2068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff
+    59a332ba58d5d5589bfe0797
+    53ee1a957eb6d6699e6b7ea2725cb2dac07ecd
+    e95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99
+    43f463f1b21cd0f9246af63db9eacb644edaa029de296e1e70d30a6d944e65ed2690d1a0abee3fc608b816f6b80cb15f044ea37d146f92f4c5
+    3b78d38c982a0c529ad66d6243694de8;
+  027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c
+    69d80ea12ff4bb5f069b8a2e86041c
+    1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba600768175
+    23bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e3395
+    d76bde841be1e0f1c79d55aba162df14df0d8d27a79006ae86206959988ee72bdc2f865964dfb9f9367c28ff87aefdd0ffa01d9d97
+    aaa345866f4b3dbee0f6213cac96bd7b;
+  8b8c2e2352fd61e4fa8fec81
+    ""
+    ""
+    ""
+    ""
+    059b6263146de5fb545a936fc848b0b4;
+  6ac861a8b33779f09e7a10fc
+    02
+    ""
+    ""
+    ""
+    58624b8c9053c43796880707b3d67f20;
+  a8f48afa3080ee119a52a9a8
+    ""
+    17
+    ""
+    ""
+    687f0761db05bcdb0388336d76fd22e7;
+  e4f2b94b0820cab383a8cffe
+    ""
+    ""
+    ea
+    18
+    767802f12d42935d7b001884afc02a9c;
+  7c486315799dc875fba578c8
+    ec4837898a92142b5b0677da1ac27311
+    7b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c88088476892114
+    50ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d40414784
+    f32ff4b45a2e730c569689c1778053d0a0d98ff6ca284a29d5dec2d196cabe0b2ff7cccd2d76677cfa6f7f3f327e95dc
+    6a8c65bf4d69020ca3653fe92b8a0750;
+  2941feeffdc2eb44dc8c0d5e
+    8f444f7f4e0c893959b74dc2
+    3a7bb40e7e0013e5150686d2301b43a15a84e8
+    1d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726
+    c4af011456e8d101166565373ad9e8f158794f83fd254b98c7c8b0fc4bf23d0c2dd3158db30946c967d9eab008d6a526e6c2bf28b0a615fd76
+    81383ad066041311a2eb1ab37d6c14eb;
+  d2810391b3f9d10c39b07ae8
+    f08ce7cee4758a386a9943e97dedfb
+    e61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98
+    edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bd
+    502ab4639cc0336813c1e56e627ca9fd05ae8a04bb2b5a5dd7c03a5a4fc64ec1b9222fb965ee6c675f52bf3815a88d8a0ab837ad7b
+    66578408dd93abb230ea3124f859308d;
+}
+
+rijndael-ocb1 {
+  ## Rogaway's tests, from http://web.cs.ucdavis.edu/~rogaway/ocb/ocb-test.htm
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000001
+    ""
+    ""
+    ""
+    15d37dd7c890d5d6acab927bc0dc60ee;
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000001
+    ""
+    000102
+    fcd37d
+    02254739a5e3565ae2dcd62c659746ba;
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f
+    37df8ce15b489bf31d0fc44da1faf6d6
+    dfb763ebdb5f0e719c7b4161808004df;
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f10111213
+    01a075f0d815b1a4e9c881a1bcffc3eb7003eb55
+    753084144eb63b770b063c2e23cda0bb;
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    01a075f0d815b1a4e9c881a1bcffc3eb4afcbb7fedc08ca8654c6d304d1612fa
+    c14cbf2c1a1f1c3c137eadea1f2f2fcf;
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+    01a075f0d815b1a4e9c881a1bcffc3ebd4903dd0025ba4aa837c74f121b0260fa95d
+    cf8341bb10820ccf14bdec56b8d7d6ab;
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000001
+    ""
+    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    4c9b676705ff2df05503872aa3d9e9b122c6b0ec060819146d9c887bad494417b63b4b2b3d9c3a4cd156856564c4a31be812a95d43e76ccf9811cc3a7613b0567bbcabf1a0f64f5245098c239ca7935765a7d402b01b671f1c600bc9a6823025c370a32da44a86911dce981ccaa7e3e720552bf8dd83918d8688e2347ba8691457bc25ab99a51a4388c3c7fad8a71e0c25fa185d2aa710dd9bb93cf2185ac950380732eef63549adcd451e70a0275b070fe1f9e338321aa57de832e1893f5febc0b2f0a6221d1aa187b9f152d20c259ed105c1a4be374993f4963074ef2676621109a03e628286124aefc8a3038b65103aa628f3e6bd6e1659ea0508185679d9a03b0794b914850cb4528293f7e992895a3e80337c23dbc95be1d3502cb9f8961e7dbe22898dc97b75fefaa75b4b3115969af05f54850489e007ce003d8023f490e37845f54d3c6dc3521fae9c34365091393f21139c96be6101a2bdc9dbc36902b5bd19686768154b011270157882f32dfef2a272be3cbf7e5d90ec1b6e374b4a4b806d83913e3df933e8caf5e02b1093b2a2991b34f98a41824a15b26a04a18f287024240d5347a2f3501546aac9c5b6e3f5010d9e2036c415d093892303050eaea499256eb83cba3ad4249537cbc250505024fe413965db1c41a77456711d50933249c63bd006716c4cc6ebf59c03c25a3ac3d06d7713c752f415f9ef59571885f38468c3f11bfd8111f839f080f544cb0c5ab9f87606287e314afe655510ceb8a62abcaef4e65e314f45b10e9858a175207356e9a8ac093f469ee587c18396f8965ce52e894b0bd29011b22f1e67abc16dcb948be141693fe31db635487285eeb4f8b4d5d13e511218759941850cd71fc898f8ba4cf1a4c23b3588dbf1e3e7c86efb113c8820e338a5d90d30c7d854a9ad7582d853d39cd3649cb67e3308c70bc75b732ae744aa126811034ff893829e554af51c83e1f004c3b7c9d0432978be459beaef6824b9cc5f370aa47b8d9edf583c3c84ef695705c95d59a428a675c5c788339ca737f2ec1cb6e83288b5bbfb6d1f81f47659f8f44118d76e900bdbc8094baa4bd950647abe22516a50bc85ea94410f985519076e34696b238262a00ebe889d58b09b81ee1f0b31f864a26978046ac24f1332559b6c5edc24748407e19f169c32d5d3f8ca6f71e4a5c2f72add2185857fde5749d5fd63f5b3658daa3dbaa1b0844fea3c8d2eb5e17febcfbfe44f4cf931129431ff51d6acce7e05107d6c055ad27beb185f7349ea060440a508b40186ec9732f84d21ae158969b671ac0d2ab823399220d75ec7cb50c29de3df974ae1e8c2465e3ecc207160c593443e424a57aaaee3c884632d979ccd0b6a239e1c3fdf777aa556a3c8815c2f8d1496a60048e2b971
+    ab335f725475e33e90ab8c1e4891596d;
+
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000001
+    ""
+    ""
+    ""
+    b6e92be21127830a690f443f5ce8546d;
+
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000001
+    ""
+    000102
+    c21ef1
+    09474d786d4640e823f52ff63ec5359a;
+
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f
+    3a709f22daf4c1bcf09cf1c2a0f5beff
+    98d49eb3468988d06d7cb32c438f1f23;
+
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f10111213
+    8e951e2a2fb4ede0397cec6ba5dad5b22137f07d
+    305767a31bc9e344f7f79843d1a268b1;
+
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    8e951e2a2fb4ede0397cec6ba5dad5b247ff19f214fd464e821c63c26e4a11e9
+    63cea28204ef06e5a21a8780ea05050d;
+
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+    8e951e2a2fb4ede0397cec6ba5dad5b235e6b8a5dcb0bd0017bfe98111352d3edf3a
+    dfec4b4ed2f95c305d59d79edbf62833;
+
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000001
+    ""
+    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    1c97d826583970d083cca433773b02c34c0e6b7127d2258435bac13100c8672db6084c02171ba72b9937b1daccd14d0db1c322c708cc2da13486d772d82d93d12b69874a220573fc25fc05922700228c475ddeae653855a2c6d5f563f6e0724b7b2fe0fa066cba3223e010c5d1a51301a2ae1047409ae88c2779967283d50aa40ebb93e07dbde704f39c76c20cd1e1970bab196eacebab67b076bf901b4ed6f6ff066e230b540737d6856472ac02dce8b7a92aaa8890a47a13fc01bbce7ff902e3a7ede4685cd9bb926fecc27e915ad900f248d7ddd3cb9bff1b589196740c35ecf330e3812a6e0fcd2fd32212b0f0515629e7165cfe64857ec5ca2ad5c6eed654e27508a2c012b726e6931c4edc1fc00dd1d609f8659b24c0b4157f43fc33761d0a9b1fb1389068b600ce2f04cf475fb4483d32902b559cc40a589e97a82417241b92199595c6597dbd0e8dc08db9b6c0323a1d07812908be90c7785c66d1b295ab772793dc7e9725ef19da40b935c6ce10e404165388db6437621ffb08246f32b85a7ee9ca8bec10e3e973136c0b99552d8713bc6c892938ad72f79341f16eaaa7c8adfe45e2c627314c256bf0554dc1651ca77a80d79603cec892ffa58b092b5134c61d6dfba2a2132c75ce56db8cb1d852330a5c4a615645281457c2020391351f8dfa1297d45da234c0549991046d888b52175e1ed2ed3619474b5b270d6b5dcdd94e1a3f20594da51c8bd564e9694cb8b498eedd7a83569da5a209ba34e0fb29c43793097437fecc07e7709c8d64f15197b241ee930652872558c7ccb8c2a0e61e40637d1d587422d5f9f8f8eb25e44f7997058c051c4288356e5dd47e6022176f83c963eac7512cabc7fc8c408d448177e1b1671c82569a2318db142f8b94a60fe5b581c6895e03397a4d9b6f117fb534ad644ef7fafab3fe34c36b5d1544df4567fa94ba7a501ed20032d567bfea10f943170e5bf9b1aac21c0e25ae5f9b98272c75a401ba0185e46ff0c9b29caeb2314a507e2664df2208beb8a5c78563f68b49c3b59b650d18eb75a22296d06943b99239521c59736a10404d458e80ed9288879545c1f9b997036b9eb76c5d75afcd494736971dd27c3f0cbdc15e8cf8337c63417f861a15c324b44fc8b3e4ef6a1924f470aefd0abb6a965451d13835e8a8d9ef94add1d2a41f42c6ebc55045d7a1c6bb0ea3af9560220180fa7b623cc2c44d5cace341746e80289e0b7321178d770e2043a5b02560328c1a01ec4ab64ff98de111c5be5516657cff2f88d3a02643a587903f28a7f9d76cceca8a03671eeecdb2aa81e59de1171e5aaae08415533ceee30aa3ec4fbd551990c074d05c390dfbb1e5d1318e869be9e8417d49ccdaf801ebd42b0309718c36deb2965311710b6d26494a
+    d28b89f5339444767d637e8f1687d204;
+
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000001
+    ""
+    ""
+    ""
+    796b5fd2716b066932371c17993dcb5a;
+
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000001
+    ""
+    000102
+    a214d8
+    e31b3449bd1b85b257b404a76b5b86f2;
+
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f
+    8ed0923f5b2c650f31a5dd422463377f
+    794904f519ab5376a30cf7771548e319;
+
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f10111213
+    6512529248df82feb506a7aeab3874f7201b6f79
+    042ac0fd6956c2b0b4205dba0b889699;
+
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    6512529248df82feb506a7aeab3874f7742c85da9d0d6cc91293ce0b333e0343
+    6a91a07cb0bf508fee08b27b5fd9f80d;
+
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000001
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+    6512529248df82feb506a7aeab3874f7ae809e2f4f88d6a6088f8d0122a7b9e723a5
+    3ba0661c8a716b550150c9effe3b773c;
+
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000001
+    ""
+    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    1464d49f9ead864d5e77ed99198302409e459f2af179c73d2f0d0855d51591cbd9555d9a8542014e2b995e5399c1f804addaff1a2c4b5afe07fd88b7095d1129cbf93f9dad20c625fab0e63788ec4634f0ae06b6fc5c56bfe1b05860e03dc3284d7e2b3190eacee799f523677f942dee5192cfc6b5dddf09a16e2ae13055e9d1ee1d159b7fcea386133de34b92743caddef8c457884a7c5034a53ee23e08aa90086824401c25646561af0d594114b1ccb6627bff630fb17a6021b4f54942ed06f06326e54408019caba8f7231200d30dc548f8ec2c80e06b13d8ebe462c1cdf1c54065afabdb97ac8d8e5a1d065c59795fb55336f01e35a6f7cf8ddbf944e31a24717977c2f9f89aba3ca1ab7559a4f732d301b678ac63c9d5388665b1f9bc56bd67b80fe21f0d6ce4973c078213456b23700725174037fe8426503b0170ce5adda0dedc80f1e5d6701384951bbed58e6ec5912cd20429c5d85c61484136caa00c5f92763414e9f1bb50efc59c834142e5fbbab07f624f28fdee284c2b7322cf3e0682731f764a049fedf2ee8486e60bbd11de998f1dfde848999c806ef779bab0468b674d395883400cc6c05cdf5b51c5fbb181690502914edc42cd4752d9c5fb524adb37149c3199f2329ecaa92006047761f01581eafb96003491fef9ccdbf637c972842645b052ece338e02b6417e25f4f93aa808ec44d8b6efdd774ebac19a1756014a9bb71da38e7743d1617e44bae076f3183c7e50f5c0fd5488cb325edd500ad5e794c469b83a4655c95289dc520797f94cd04e834b1842f769236522cf79ae63ad4664b4745316142bc74ab27be915194eff2a2a1d740c83bffe28b8fe6cd1382ca8de806365275ed05baca90484b03ee87624f072905b69587c05be58aefd4e367257aa95ce3a6d0f65a5e7221c8f729727e3bd66f3d9e33f0d7b8f03ad31e62c837599e062a4c8681ec3276c31d58f2f3f2dd018b3c579fe50d7f911f8665bc064a08ae8ff6d87440e088b2162733ea6066ac70309600819f3f429232bb26376303fc82cd198dfc92382cfb3c8bc245984b845c51e6b5da8a9669e1d961f7182d0bb9757a99c0d72d4c037df2ca29661faf0db89fdce75bfb67031522096ce88f1ca6740f3dbbfd65fdf674a547d82d331abaaf1c5f0742a25c6f5ee0cfe288fb93e76d2fab4fde4904c2967303fcf2adb8bbd333b33728aca04b60dabdd08e0acafaffa97b02cb011db94687afa7bed3157d3a90814eb00e55b39cabfe9ef35bae62c80ad225cc34a0d7cce13c55ac107d00d7b37562222ac5d94cb73ff20d8947fb8ec63735280c0ce31aaca8fee02666f7a6fb2b44f1ebe0f090050f1036877ddb6705b1b622dbd1742f8ed2d985a5aeab4cd2a0e68d1ec3c6c1fec66446150d44
+    826d7f68f3ce28e1e98191e92b23ab0a;
+
+  ## Homemade tests made with my toy implementation.
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb14ad
+    ""
+    ""
+    ""
+    bbdd78ab7b6ed33bfbaf8438bf9df7ee;
+  568f86edd1dc9268eeee533285a6ed81
+    0c9b689daaa9060d2d4b6003062365b0
+    a5
+    ""
+    ""
+    f7922af46325a139e69abfbb9b999c4f;
+  4364c76c160f11896c4794846ecfa14a
+    7130c9f137120634c9519848a877ff77
+    ""
+    bf
+    98
+    8c5a791452eb9c1f37d7ab1bf637c432;
+  79192a5b50ade5d9cd739a3d1f337f29
+    549e6b0d27a4ba234085406a61365120
+    ""
+    61f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9
+    bed87d0e2b6ab736c20081f2041691cdcaedfff9cdb08f5ff2b443fbb4990690a9bb03b8b801d3562f037c61c6d40929
+    bd5b4d2c9aeae8e9dd6baf02c53cc96d;
+  ff61cdbda3b3e9878731ebfedd4705e5
+    05da1435dceaa7b1cc49ae1d50c38201
+    a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc
+    520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605fae
+    b6cbe859f09a407e4a0e376a41b18a84eb07874e1b280fa3cdffa733c207c4b67ace2b90a406b1df6a2389593134796d
+    f370bf6c86cae4c4248040d74c191392;
+  e2b03fb648e27fff63102758fe2b69ac
+    26afa3349829b94586306fed54154f8f
+    ""
+    28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcb
+    2ca95a4a033cd358788f8ffd43bbf820dc0982dfee8583eead310d571cb87e4472331362ff6820abf76cab3b4f405b41ad167f864d
+    e20d6b13e4691b43b82d5e16f77366b9;
+  aca48b77dba189196d1ebba10b0467cb
+    9fc2712a199e533fa9156308cdec3f76
+    8281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95
+    214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063
+    8c3ebaaf931dd282e77df4bf8c242a81593282df72cf91df24dc0bd8f6559f404058b9885529821083839944713def901330eebe75
+    2d965094a4c93d801be22ba3faa198d9;
+  c46f88de9fd41e72d7b97e23e6eabdff3bcd2114
+    99268878dbf30f1dad89d4b9b12012e4
+    ""
+    ""
+    ""
+    8d524a5f17704ae5983de23c8c09fe82;
+  713df46795630e7952d22bb02d7100b8b649377d
+    20a8f083455b663e4ee1315f3c8f2aeb
+    fa
+    ""
+    ""
+    9ea050885c272134d9056a4a94dba2dc;
+  921451dcd1af5813b70d30ce2f1fef6ef315d079
+    8391805da08da3aefc5f8584b7c5e617
+    ""
+    66
+    93
+    813637682fa8878156badce86a0243fa;
+  9c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb
+    16c2e815f422cdf0c8e30308be3c31e6
+    ""
+    bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446
+    dd538bb0839a0a7925c5a2aaf2cac28de820d307023f2ab4f2ffa04cef224b155ab948ad399e65a9ea8477aea35f29e2
+    e00806f1d623829ca51eeda7493528e9;
+  b42fb144d44b6d00f06dc188d472a784e0c6f211
+    95a3b9f4ae985511265febd11c164720
+    eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a
+    9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd1901073147
+    4a2e9698c0d7ac74177739a07570f0f6afd2e3f3b6e9badbdbd95fdfc747dbbc7c1c8bceb40e423e1b2fa560ed2da50d
+    f13efea41ebf09ce14655687cb20a908;
+  17a77456f3ff669c732b58db8f48af65f7cc9e3f
+    b90e1721b730374ffc9bc597f56ccbb2
+    ""
+    f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd
+    672edb9395d87cc48fab9727017091e7a6d09f7977fbbfe77f9669485aaeca7a4d54662565aae03033ae925528e9880d33766cafcf
+    a8ff24657308e7d34115b33ff27ff795;
+  1ff6778554acf1270485b203a3c1c4c967c0a458
+    cb948bdd409b687fa3a6827b480aa3a4
+    c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205c
+    dad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41
+    367a16e4adbc471e15eed3d0415714c61a67e93f44b5890d17f9d29991bae8406d317e7064c765278d7370f6534462f6eb2db66b23
+    79a7bbc9be788ebb4b94fe94f3f74439;
+  cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdc
+    ccd213e33f7e8a5718fd25014107c8e7
+    ""
+    ""
+    ""
+    12f235dbf2dc24a51ec9211ba16494bd;
+  d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9
+    f891bc5ba5afabf8c3122d12d7ff3c41
+    12
+    ""
+    ""
+    eb5d7e61788af1e2d62a0023cbee8ce8;
+  2d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d669
+    9e6b7ea2725cb2dac07ecde95759ac46
+    ""
+    fe
+    65
+    80cbf647b155069f455e35ce699db1b6;
+  e6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9
+    cf44bbc8c6254d980398bd94e66eb456
+    ""
+    3d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86
+    5b2913b5bd5d4155174de957631d366c398a890cdcdef62c8a7882229522d3b944a1b0cc2d958910469f001ff60f4d05
+    fd4cff3dc0c58f0743b0bd9bc4e7b346;
+  041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15
+    ffaa6c36800d9645563a308ba6007681
+    7523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd
+    56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b
+    79b025b6d15120b9cc79ceb62cfe0479248b47f4b6318deeffe7ff11688460479331326370bac61dbec32ba5571d65d8
+    ce1ea3a0bfda4a072c98376f259ed0d3;
+  0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a9214
+    2b5b0677da1ac273117b45bcfff5d5f8
+    ""
+    b6fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22
+    42075fba1b912e07c6f10e6356f6ccc84c60f34ea054dec4e4cdc39eb8f5066218b61d9cd799d28281e84d2d5f0138c944f1074b2a
+    2889c19baf58c2061aa386bb60bf5c94;
+  ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0
+    e80f678d404147842941feeffdc2eb44
+    dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e241
+    4ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391
+    b270a45c7bb349e1dfbc9226da556d1916cb8eee0acc23671a875ba1bab176be7067e6ac38c492bef6c908881eed86e3fa34ba13bf
+    dd48047480fa2218d080933718dfa7dc;
+  b3f9d10c39b07ae8f08ce7ce
+    e4758a386a9943e97dedfbe61e737882
+    ""
+    ""
+    ""
+    aec3dd3d7d4d41c121f6da813bc52c6f;
+  cd09c2b9a80f34c0fde11c24
+    81b11fc76bfa4dbf710a9e544e0c536c
+    a1
+    ""
+    ""
+    1fb81cfb59ee9a075fc17a01fb0acb9e;
+  e040f9ad5b04140d98edabe0
+    8485290a4d87d13b07398a1458c2c6b6
+    ""
+    1d
+    cc
+    2efc465c99ba1057c7dce6bf82f04a7d;
+  bdbc1cccada8c1a0a9aabb6c
+    4e3c3554f8fb1ef61614c270295dfc0c
+    ""
+    a6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae4
+    c5b165d12e4f62edf355fad299ca25ee317c7c65deea43e27c93f43f66d87364b7dc60d20d5bcfde11e982c9275b2ebc
+    5536fc1ce20b189e094233fed7a3da05;
+  80cda98ad6cf2bacf6f9fd3f
+    821330c43f3df6c2b3fac7cbcf96523d
+    4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59e
+    d034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197
+    03cf2190ef314c60a1b51ab9c6d6cf1613779e05cb1f6dd1b54b16f1cebf6b964ee6f21a606b72e5751723d5ad6e284b
+    7eb35f7458437efd2a95c97817396485;
+  a21cc34ac0d5ae7be8dbf98e
+    4ffed2cf6b1372a5aa47b54fd9d70c70
+    ""
+    e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1
+    8a8f9e2516855b74721de0ee915f1759ae9aa036c52d9cbe43111de9015eb6bd353bef5bb4df325f466d8e2bd09303f912bc0576be
+    c67bc656ea1b155208501e080120205b;
+  406d465b7b1419ea51cf858f
+    938f6daafbd656445a09898eaa96ffc3
+    d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538
+    e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a95
+    15d8d8bfdd4b5fbe0885d060fc15bb2763c2d4aad2d18df548ed258db51d9cfd866b4e7798650061e447291f45ebe5da37635d468d
+    329d67984dc92e926bf2c0698fba9e2b;
+}
+
+rijndael-pmac1 {
+  ## Rogaway's tests, from http://web.cs.ucdavis.edu/~rogaway/ocb/pmac-test.htm
+  000102030405060708090a0b0c0d0e0f
+    ""
+    4399572cd6ea5341b8d35876a7098af7;
+  000102030405060708090a0b0c0d0e0f
+    000102
+    256ba5193c1b991b4df0c51f388a9e27;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    ebbd822fa458daf6dfdad7c27da76338;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f10111213
+    0412ca150bbf79058d8c75a58c993f55;
+  000102030405060708090a0b0c0d0e0f
+   000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    e97ac04e9e5e3399ce5355cd7407bc75;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+    5cba7d5eb24f7c86ccc54604e53d5512;
+  000102030405060708090a0b0c0d0e0f
+    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    c2c9fa1d9985f6f0d2aff915a0e8d910;
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    ""
+    0d63b2b2c276de9306b2f37e36dabe49;
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    000102
+    5b1cbc4340752742d8828a7aa2c3197d;
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    000102030405060708090a0b0c0d0e0f
+    0787415737989bc1a2e124c991e400e1;
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    000102030405060708090a0b0c0d0e0f10111213
+    156a7c21121cc773a731e05ab618c6bb;
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    654a145904dc97da9f68318b180970b9;
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+    b5ff2016878e834438aa1ff624bfa09c;
+  000102030405060708090a0b0c0d0e0f1011121314151617
+    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    d3aec29036298bc11a2905f53773ff50;
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    ""
+    e620f52fe75bbe87ab758c0624943d8b;
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    000102
+    ffe124cc152cfb2bf1ef5409333c1c9a;
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    000102030405060708090a0b0c0d0e0f
+    853fdbf3f91dcd36380d698a64770bab;
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    000102030405060708090a0b0c0d0e0f10111213
+    7711395fbe9dec19861aeb96e052cd1b;
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    08fa25c28678c84d383130653e77f4c0;
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+    edd8a05f4b66761f9eee4feb4ed0c3a1;
+  000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    69aa77f231eb0cdff960f5561d29a96e;
+
+  ## Homemade tests made with my toy implementation.
+  60d7bcda163547d348b7551195e77022
+    ""
+    f179b2c8e7020f9992e161128568d833;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    335ab1737aaadac9f7d949ab7dc22fb5;
+  8f86edd1dc9268eeee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77
+    bb8edccea3819962f3207d2494d63229;
+  bf79192a5b50ade5d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21
+    2ecd8200722cfe2378e956131b67d64e;
+  635c6d62c9269029df3e6057acc87638f5080467
+    ""
+    5defdf6083418cf3d45824aa490a4d81;
+  33d9ff61cdbda3b3e9878731ebfedd4705e505da
+    14
+    6c60b9db748a6bdda7823422ed13e4cb;
+  35dceaa7b1cc49ae1d50c38201a894476b3f102b
+    752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3
+    c20cac43be40631325f8d7c9e65991ad;
+  a4f3ebbbb18ac6c95a97a48030370c33d090c542
+    15abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829
+    3c963d5d3230ef4dc33ebd19f63965d9;
+  b94586306fed54154f8f28523c03d4de1600157846b710ee72807a22
+    ""
+    050092b5cc9a2d131ea4450c057bbf3d;
+  19bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d
+    42
+    16501f8ba884f8ace15138cefd2639a7;
+  f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e
+    533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5c
+    9738377d0ead6012bac60ae10ac4e5f7;
+  fb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc81517
+    84873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6
+    709f56ce90034a8882bebbfe453452c7;
+  eabdff3bcd211499268878db
+    ""
+    697879320c2ee020acf13693df75c31d;
+  f30f1dad89d4b9b12012e471
+    3d
+    453c840a1c34bfeff73a653ad97150b4;
+  f46795630e7952d22bb02d71
+    00b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da0
+    aef316f092694e691d9fba0324d8397a;
+  8da3aefc5f8584b7c5e61766
+    9c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb6
+    0638371148ba4e00b0cf138e026a7740;
+}
+
+rijndael-ocb2 {
+  ## Taken from https://tools.ietf.org/html/draft-krovetz-ocb-00.
+
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    ""
+    ""
+    ""
+    bf3108130773ad5ec70ec69e7875a7b0;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    ""
+    0001020304050607
+    c636b3a868f429bb
+    a45f5fdea5c088d1d7c8be37cabc8c5c;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    ""
+    000102030405060708090a0b0c0d0e0f
+    52e48f5d19fe2d9869f0c4a4b3d2be57
+    f7ee49ae7aa5b5e6645db6b3966136f9;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    ""
+    000102030405060708090a0b0c0d0e0f1011121314151617
+    f75d6bc8b4dc8d66b836a2b08b32a636cc579e145d323beb
+    a1a50f822819d6e0a216784ac24ac84c;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    f75d6bc8b4dc8d66b836a2b08b32a636cec3c555037571709da25e1bb0421a27
+    09ca6c73f0b5c6c5fd587122d75f2aa3;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    f75d6bc8b4dc8d66b836a2b08b32a6369f1cd3c5228d79fd6c267f5f6aa7b231c7dfb9d59951ae9c
+    9db0cdf880f73e3e10d4eb3217766688;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    0001020304050607
+    0001020304050607
+    c636b3a868f429bb
+    8d059589ec3b6ac00ca31624bc3af2c6;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    52e48f5d19fe2d9869f0c4a4b3d2be57
+    4da4391bcac39d278c7a3f1fd39041e6;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f1011121314151617
+    000102030405060708090a0b0c0d0e0f1011121314151617
+    f75d6bc8b4dc8d66b836a2b08b32a636cc579e145d323beb
+    24b9ac3b9574d2202678e439d150f633;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    f75d6bc8b4dc8d66b836a2b08b32a636cec3c555037571709da25e1bb0421a27
+    41a977c91d66f62c1e1fc30bc93823ca;
+  000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    f75d6bc8b4dc8d66b836a2b08b32a6369f1cd3c5228d79fd6c267f5f6aa7b231c7dfb9d59951ae9c
+    65a92715a028acd4ae6aff4bfaa0d396;
+}
+
+rijndael-ocb3 {
+  ## Taken from RFC7253.
+
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221100
+    ""
+    ""
+    ""
+    785407bfffc8ad9edcc5520ac9111ee6;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221101
+    0001020304050607
+    0001020304050607
+    6820b3657b6f615a
+    5725bda0d3b4eb3a257c9af1f8f03009;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221102
+    0001020304050607
+    ""
+    ""
+    81017f8203f081277152fade694a0a00;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221103
+    ""
+    0001020304050607
+    45dd69f8f5aae724
+    14054cd1f35d82760b2cd00d2f99bfa9;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221104
+    000102030405060708090a0b0c0d0e0f
+    000102030405060708090a0b0c0d0e0f
+    571d535b60b277188be5147170a9a22c
+    3ad7a4ff3835b8c5701c1ccec8fc3358;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221105
+    000102030405060708090a0b0c0d0e0f
+    ""
+    ""
+    8cf761b6902ef764462ad86498ca6b97;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221106
+    ""
+    000102030405060708090a0b0c0d0e0f
+    5ce88ec2e0692706a915c00aeb8b2396
+    f40e1c743f52436bdf06d8fa1eca343d;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221107
+    000102030405060708090a0b0c0d0e0f1011121314151617
+    000102030405060708090a0b0c0d0e0f1011121314151617
+    1ca2207308c87c010756104d8840ce1952f09673a448a122
+    c92c62241051f57356d7f3c90bb0e07f;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221108
+    000102030405060708090a0b0c0d0e0f1011121314151617
+    ""
+    ""
+    6dc225a071fc1b9f7c69f93b0f1e10de;
+  000102030405060708090a0b0c0d0e0f
+    bbaa99887766554433221109
+    ""
+    000102030405060708090a0b0c0d0e0f1011121314151617
+    221bd0de7fa6fe993eccd769460a0af2d6cded0c395b1c3c
+    e725f32494b9f914d85c0b1eb38357ff;
+  000102030405060708090a0b0c0d0e0f
+    bbaa9988776655443322110a
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    bd6f6c496201c69296c11efd138a467abd3c707924b964deaffc40319af5a485
+    40fbba186c5553c68ad9f592a79a4240;
+  000102030405060708090a0b0c0d0e0f
+    bbaa9988776655443322110b
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    ""
+    ""
+    fe80690bee8a485d11f32965bc9d2a32;
+  000102030405060708090a0b0c0d0e0f
+    bbaa9988776655443322110c
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+    2942bfc773bda23cabc6acfd9bfd5835bd300f0973792ef46040c53f1432bcdf
+    b5e1dde3bc18a5f840b52e653444d5df;
+  000102030405060708090a0b0c0d0e0f
+    bbaa9988776655443322110d
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    d5ca91748410c1751ff8a2f618255b68a0a12e093ff454606e59f9c1d0ddc54b65e8628e568bad7a
+    ed07ba06a4a69483a7035490c5769e60;
+  000102030405060708090a0b0c0d0e0f
+    bbaa9988776655443322110e
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    ""
+    ""
+    c5cd9d1850c141e358649994ee701b68;
+  000102030405060708090a0b0c0d0e0f
+    bbaa9988776655443322110f
+    ""
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    4412923493c57d5de0d700f753cce0d1d2d95060122e9f15a5ddbfc5787e50b5cc55ee507bcb084e
+    479ad363ac366b95a98ca5f3000b1479;
+
+  0f0e0d0c0b0a09080706050403020100
+    bbaa9988776655443322110d
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627
+    1792a4e31e0755fb03e31b22116e6c2ddf9efd6e33d536f1a0124b0a55bae884ed93481529c76b6a
+    d0c515f4d1cdd4fdac4f02aa;
+
+  ## More tests, made with the toy Python implementation.
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb
+    ""
+    ""
+    ""
+    7d2702e740fddada3e57a788402f9d44;
+  14ad568f86edd1dc9268eeee533285a6
+    ed810c9b689daaa9060d2d4b6003
+    06
+    ""
+    ""
+    c129582b8bd54dd2e80592f467112495;
+  2365b0a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c951
+    ""
+    98
+    8e
+    27a9a3f75d1f36a156c714d820d0b3ed;
+  48a877ff77bf79192a5b50ade5d9cd73
+    9a3d1f337f29549e6b0d27
+    ""
+    a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e60
+    fb544221d7bde1ec31564a9580440c902d76a7df1eff12955d17995e9bfe2336d4c2eeb42a6656dd37200ce5ff9cabfe
+    0f9ff860aba97bfab2845af16558883f;
+  57acc87638f508046733d9ff61cdbda3
+    b3e9878731ebfedd4705e505da
+    1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa4
+    50727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54ef
+    08584d252daf79311ca8d694e33e04711f723c890a222e7ce75ff2842e87e39d714934e8c6dc3640ffc5cdad1634063c
+    679f104fe67c507aec33a0e15b589bc2;
+  c9a38378c5b93bf4f2aad2605faee2b0
+    3fb648e27fff63102758fe2b69ac
+    ""
+    26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b
+    63c2bf2254c696b288b0f41fb5b44bdf45914dce25d0071438069dbff337bc844506e5a47a28c700500280c08c54a5e4b43118ce36
+    b9fde958caee8ea9cdbe8425ddb382ad;
+  571ea629c54d57dd2d42f70800df9fcb
+    aca48b77dba189196d1ebba10b04
+    67cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a2226
+    0c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b
+    a459d6659d827b523dabbc0a66cf8c151764b24a59199a6d8e4a161ace110c683dee759f823be08f0538fce282d036d2c7653ecb91
+    63bec719103775440457715faa831368;
+  5337685a96ed65b9aca338527ef19b09c063c46f
+    88de9fd41e72d7b97e23e6eabdff
+    ""
+    ""
+    ""
+    cc2b3f40254925c2e221259c3b6e8df2;
+  3bcd211499268878dbf30f1dad89d4b9b12012e4
+    713df46795630e7952d22bb02d71
+    00
+    ""
+    ""
+    272e89e7297e08da41d775d62b336e80;
+  b8b649377d20a8f083455b663e4ee1315f3c8f2a
+    ebfa921451dcd1af5813b70d30ce
+    ""
+    2f
+    cd
+    3c1a46e21f59810999d3ef51f0460322;
+  1fef6ef315d0798391805da08da3aefc5f8584b7
+    c5e617669c0f16e39815d4
+    ""
+    e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69
+    b75d269e9b2a080fd4d34bf0f8e7007e289b3f84ae1b8b6635fe27c5121605f12ab038a2fdfe7e29128beb944fe01b4f
+    0e98f9a81eb34cde7f67bf40e05b6058;
+  a4cd52147ed12ca986981a874498ad0abef8bc4f
+    cb70e27e98ef1f0446b42fb144
+    d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00
+    456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6
+    a4b540f15bcf54450c71860ffb180accc2b9218e4780a80b11cda67f1c38c8a9a8b0c5d42b243c5007b1832868dc1212
+    9fdcf861176e933b53461b27aa00e837;
+  daa089c3f9099c5ffb824173d7634c04226f30cb
+    b7f0e4a973a8cd190107314717a7
+    ""
+    7456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0c
+    9897c9d1b74b1f19e984b37cfb2823670e662d5b26bc7216a174fe2bdc87b7ae8e76f57b71cf8ef83d9f7da96a5f470d6b29b62f06
+    cf1f7c7135e2f593a2b66800fbf07ee8;
+  ae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f
+    0911e32d65cc1770a18cbfe6effd
+    1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b5
+    3bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451
+    7df3a815613704e6db80308c5e5161430a724f4a11dee60f9b0519f96f29c8c6fcf91443f230d7ee8fd8206e0c71161e9d770d5586
+    e54a174b4a61d1ee1faffa2dd7a59f70;
+  399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65ba
+    d397abfaf529ee41cf9a05c7efed
+    ""
+    ""
+    ""
+    74e3172048a0aed02ad958e79920884b;
+  ef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e
+    8a5718fd25014107c8e7d715a92a
+    dd
+    ""
+    ""
+    148ca2d47df2264f1aba1b2b374aad1a;
+  9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5
+    afabf8c3122d12d7ff3c41122d70
+    ""
+    d1
+    f5
+    4c185af3fa049730ff516d35fbda064d;
+  7d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7e
+    a2725cb2dac07ecde95759
+    ""
+    ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d
+    64e99a93b20ce72c4e9da3b335e722e85aeb922ace51720c32f4edb402571244d7d1e4f3d2bae1baa06da5ec6d7368ec
+    bd4509f46b03609bd11124376731fa19;
+  405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b954
+    60938de1288c69d80ea12ff4bb
+    5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba600
+    76817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973
+    ede69717cc474d94579f3aa442ecb523504280aa8dfb5604e81f8f18c5aee67140400e27ee7aa624cc3d2f8bd8eb1dc8
+    e3472e0b88ee37919d72e8a29553274d;
+  accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f0
+    9e7a10fc02a8f48afa3080ee119a
+    ""
+    52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6
+    6ea42fed3a9e40ae5bd32e3513e027f791595675af5e77e0044070af2ce0ca4e1facf77f6b7f0c16b2c3c528343a9c7c6d1352517e
+    476ce6884dfa2a97ce67aafcc3375ea6;
+  fde2893232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2d
+    d721c0095c8808847689211450ba
+    8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d40
+    4147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2
+    17fa00469b04d4b9563e87be4bd5f9cffd0238adb9ee98938dabb0528e0fa95fc3cf499e67d4d19606242736d8e776bd5357a0d48c
+    c8ef4f4fccad46f7fb55786818991586;
+  414ebf47970e560475cff206
+    877de69146acc3ab6cf8556b7aa7
+    ""
+    ""
+    ""
+    17c75f5f7d6d099a7d375b9ea6ee9fc6;
+  76945948d1b8834df2196c92
+    ec1718dcdeee0d52d9539726d281
+    03
+    ""
+    ""
+    2abbc7c4cac1b870f9e8a92f00f1f2f9;
+  91b3f9d10c39b07ae8f08ce7
+    cee4758a386a9943e97dedfbe61e
+    ""
+    73
+    f4
+    8ab448b5400b1a46c7c5e20ef9700e22;
+  7882cd09c2b9a80f34c0fde1
+    1c2481b11fc76bfa4dbf71
+    ""
+    0a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb
+    7c8660ca8ca219cd98abe715c166df757edad193c7d1a6f9227d7633b1666bd34c86f6df7819a80903e5c37ffc5e0648
+    27c846118776e3626f15532888d3f887;
+  6c4e3c3554f8fb1ef61614c2
+    70295dfc0ca6551ca4bdb75359
+    f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bac
+    f6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98
+    9c912ef9d07d26881c823aecb92e81cc988fbdd1292d49ae9cddc5c1fa5e1a618c96e71c64866481926bc83c1c2ec172
+    b7f45c7b104609fc3be061ebb388ee13;
+  cedbe88e245de25b1593b70f
+    8601562d90a9b59ed034a867642d
+    ""
+    25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf9
+    00bfa16e1410e13d46752a90f40b6d9f6193cf06930ecb55abd2f973b710fa0582b30f87e5edc850a652def300f06da79231471399
+    b8858413846d2de7fa4654376b1b9f1f;
+  8e4ffed2cf6b1372a5aa47b5
+    4fd9d70c70e117bf1cae71b3a56f
+    0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597
+    a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe0
+    9cadbe9441f1705005b73f4e5b1675fc77390306e768a3f599a8fb11846ec535f0fa52e88120d3409912c342401b16a395784c6dcc
+    44773033baea19b7a13cfe0f67d9da85;  
+}
+
+rijndael-ocb3-mct {
+  32 d90eb8e9c977c88b79dd793d7ffa161c;
+  28 a3c8ceaa94b405effc970e05f15fa2ff;
+  24 f673f2c3e7174aae7bae986ca9f29e17;
+  20 c8bc484858c5b1bc9e4241e2f552b371;
+  16 67e944d23256c5e0b6c61fa22fdf1ea2;
+  12 2e9806312d331fe78476fe88afb74763;
+   8 2cfce691258f4d0300c220a6ef4d0a81;
+   4 5d36742a2f065dc845789585f81f052f;
+  32 5458359ac23b0cba9e6330dd;
+  28 a14417b0bad703c8d1eccd2e;
+  24 05d56ead2752c86be6932c5e;
+  20 a61001205f451947258a950d;
+  16 77a3d8e73589158d25d01209;
+  12 6a32e20692f16b31a51cff6d;
+   8 211b29176d56d0528fd70c9f;
+   4 db638b2ddc074fe1ec1056d3;
+  32 7d4ea5d445501cbe;
+  28 94d6f38a6bcf4fa0;
+  24 0066bc6e0ef34e24;
+  20 1a583bc011e8a4fc;
+  16 192c9b7bd90ba06a;
+  12 385bcd58e8387991;
+   8 2fb22e566436473d;
+   4 c00b55e9a2bed310;
+}
index d7732ff..4210f73 100644 (file)
@@ -2882,3 +2882,931 @@ rijndael192 {
        df6e46c2dbf69f357bbe22bf604efca58a7352a18f41a7ad
        1d5fa8d85dc2428dabb69eb4c9cea7180f2fa554eadb9dc4;
 }
+
+rijndael192-cmac {
+  60d7bcda163547d348b7551195e77022
+    ""
+    60b69a71abf68553087a4635c8f3d6a6445330a424fcd5bc;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    a70f592cc5ea00d17b15fa9810fd694c21e9df121ef3b4b4;
+  8f86edd1dc9268eeee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba
+    872bf13b5f881a915c9342329f04911369c818c0ea171840;
+  234085406a6136512061f7080cc07df0
+    591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49
+    8b456186aa6c2a0d7595f606dc18e4934435f659d05d8994;
+  ae1d50c38201a894476b3f102b752eb952953396
+    ""
+    2d401a31a7641d7793074c1fd8f49be54d4b542aaefaa85b;
+  6f27043eb621b7f65b000961040ef2f9b2fc5fa4
+    50
+    f6433b85e1c5134170efabaf9787fbd7e65cb12ce129d440;
+  727a9b542cde52ebfda19d0ccc520f215eb57bb3
+    a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f
+    20c4e9333e614096c96a21d83ef6779616d99f93167fd455;
+  8f28523c03d4de1600157846b710ee72807a2219
+    bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f7682
+    a7ae91664738b763e5d45d556edd0b59923f159dc9cea08f;
+  81e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a
+    ""
+    558b741080d1a886fd8798f4100853f2004201a48be08907;
+  42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c
+    03
+    e115710b82135a9cbc43aefae273556dcfb62394c78417a6;
+  7ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9
+    aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b
+    22ac79b7ae3011dc8a14b3516edadac8de849d9599fefa6c;
+  663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef3
+    15d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e4
+    57c8bb706e09c6ac44146a999925abef54403c8e610efca4;
+  7479a684b5aefa69a4cd5214
+    ""
+    afde241e1a29decdd2f924776073a7108b90a02528d9db4a;
+  7ed12ca986981a874498ad0a
+    be
+    37beddab340f4b5245afc8b5a0fd78004ffcdbdd2f3a41e5;
+  f8bc4fcb70e27e98ef1f0446
+    b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc3990844
+    4d27aa546ff3594eeaf076a140cf3e38686d4d9b2d9f75b5;
+  5608fe95e81c2533e31c9c1a
+    9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e
+    3848a7fc35a38ec5c202692eb9cc03067f1e3a587996a2fe;
+}
+
+rijndael192-ccm {
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb14ad568f86
+    ""
+    ""
+    ""
+    eb328a4c;
+  edd1dc9268eeee533285a6ed810c9b68
+    9daaa9060d2d4b6003062365b0a54364c76c16
+    0f
+    ""
+    ""
+    b2ac3bb1;
+  11896c4794846ecfa14a7130c9f13712
+    0634c9519848a877ff77bf79192a5b50ade5d9
+    ""
+    cd
+    d3
+    2fe24f74;
+  739a3d1f337f29549e6b0d27a4ba2340
+    85406a6136512061f7080cc07d
+    f0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c
+    6d7e47a271f0a9140ab83f9874698af802509e3ce08ae633274ec72ba7fc0439a766245ae5ea7e1581432240c5e9400e5d4da1d9f3ab8d203cf35bbc9bdc48354be9ab81d3c97197
+    fa0923d87206b84258099d69261e1f86f7da4740051c5087;
+  33d090c54215abd6b3ad54efc9a38378
+    c5b93bf4f2aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b57
+    1ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42
+    3fc60a985fd9a0b75ff268e4dbf8c87195dcd97029ed59b6a8592fac9a954fd250025e1cb3fb3c7d509e327ceedf08d3c90467a66f23c7a45369ce96c0450e44b09434979c7962c4485c2b2bbf
+    54ae41dbd56b7171107397fa7f4aa3a81f889a179161bcee;
+  bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f
+    5fe8368131115c037ba323fe1dc8151784873f
+    ""
+    ""
+    ""
+    b65bbb04;
+  0eb5b647da6794c18b5337685a96ed65b9aca338
+    527ef19b09c063c46f88de9fd41e72d7b97e23
+    e6
+    ""
+    ""
+    d1f9ef31;
+  eabdff3bcd211499268878dbf30f1dad89d4b9b1
+    2012e4713df46795630e7952d22bb02d7100b8
+    ""
+    b6
+    f8
+    3b797ce2;
+  49377d20a8f083455b663e4ee1315f3c8f2aebfa
+    921451dcd1af5813b70d30ce2f
+    1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e474
+    79a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720
+    7b80a5b2f5259f81e3e755ac7afcaf2dfc39714c0b17a69c8a126fcf854ce88936114c5309af3ebc4d06437399884d56edcd0d5d89c0106326b3f801ac391c6ecfd167efc7d1b7d7
+    4b5a71ab534a4ae72dd6709be87c69173467728ed407de1f;
+  eef9eb1c8dd0b00951f284649016ed0045633185
+    4bc78bf43966eb0cfa9138ddc3
+    9908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456
+    f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc
+    24d3d61a7ec5951c8e7687bf216082e306d71c7a9351d45e7272418a2e4a22c8d5f5255abc0f1f081919b0910596727bc3ac57f0f4e55d562144ea20ccac5c640ea08baf53f71e35faaa8d75f0
+    65337469537455c0488f31bdad41f2bd174c2b890dad1d33;
+  1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458
+    cb948bdd409b687fa3a6827b480aa3a4c84cef
+    ""
+    ""
+    ""
+    773f8182;
+  64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8
+    deb9bd205b70e04c091d205cdad9e9a79b1abf
+    91
+    ""
+    ""
+    1bad4133;
+  b0851e5ca605ac8451399587011677508a15dde524af3e2bee064654
+    1a42c2ecccb44d65bad397abfaf529ee41cf9a
+    ""
+    05
+    41
+    fdcd5753;
+  c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213
+    e33f7e8a5718fd25014107c8e7
+    d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6
+    699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8a
+    7f1ac5936bacdff5ab2339c74028aedc3266926aaa6685e9b688b5ac499d1a6912f4c957dbad07dc747ea4b9855f7656fd6952cbddb4a0296cf2e58227e0c05fad7d373f3a6a081f
+    bc33380a30663863f7d96afb80b51b7e89b08bbe5d523f62;
+  b9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80e
+    a12ff4bb5f069b8a2e86041c1b
+    9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc6
+    67a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cf
+    055eaaabcac3b8d64c9d744eb534ea4259d6c114554cf28dee96aa729da5b70556f4a9a8724506b42fe6b2d266db7cd0b904881f7dcd312ea17e9d256e14fc40d8d6a6286cbcc3772cb3c79f25
+    72c96466655bf5d891fab5d415bc6065d3902ca0b8f95a40;
+  feea7c486315799dc875fba5
+    78c8ec4837898a92142b5b0677da1ac273117b
+    ""
+    ""
+    ""
+    bcaf4c92;
+  45bcfff5d5f8b6fde2893232
+    a9f81d14517ffae475f6b94a43a67b3d380d2f
+    9a
+    ""
+    ""
+    25f9961e;
+  aafe2dd721c0095c88088476
+    89211450ba8095ffab1eaadf66fd22ac197606
+    ""
+    3e
+    10
+    e0be6bf8;
+  113ab61f813e28a1397a7974
+    a1d7f4220c785fe426a5a0e80f
+    678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de691
+    46acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f
+    633bd657368c964b774d76c9a8deef5e79c2db8c3ba300ff01b9a1685cb5688f8477c50bf62f380d5dcbf7e9fef05b73415e446f8675dcbd02c9a182b3647d7fc7e5320b9fc480bb
+    f3a1b675f8b96ce151ef507f6a587f4f9d78db3df352eef2;
+  34c0fde11c2481b11fc76bfa
+    4dbf710a9e544e0c536ca1e040
+    f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d9
+    21056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c
+    77d68b7c74c11fa6f23cab03c8e20965e7362191f15a359371f06954d0a8673d43d291db49563e5775d590a5b66a4de2c79fa96da0bbe7b18ff98fadead8cdc6bf8f559ed3675d46cca4cb27f3
+    828d1b75c068055451d00b6a0e8a5b0e5672f780c282a170;
+}
+
+rijndael192-eax {
+  60d7bcda163547d348b7551195e77022
+    ""
+    ""
+    ""
+    ""
+    4f06617fd2435935d07da73b3fa4147dac1325a119046009;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    ""
+    ""
+    ""
+    91538eab427977388accbffddc6478f21b5fecbc6c7cb90a;
+  8f86edd1dc9268eeee533285a6ed810c
+    ""
+    9b
+    ""
+    ""
+    e5c24c4b113407583e10b409e553d653a5a519cba5f6d500;
+  689daaa9060d2d4b6003062365b0a543
+    ""
+    ""
+    64
+    b2
+    04d4d6804877ab6f6b3fa8566da51a683626144b1f15b0c9;
+  c76c160f11896c4794846ecfa14a7130
+    c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd
+    739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff
+    61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde
+    5ab0c81553820168ce731c21e2d27c369cee4e9e62ad20e90f838e1e625efa976022de1063b1eea5f4b80f436fa05ff63b8805ccffe979d6d3809360b85598694b0e56f834aa44d6
+    4808e60011165622ccfea271b2720944612f7ba9fdaeff2b;
+  52ebfda19d0ccc520f215eb57bb3a4f3
+    ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad
+    54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689a
+    f741602c2f1d8e46421651f6022a8c5525619a3231ccc623aa9220867f029b7fb8ded5cf9ecd06524d68399fad71cff1f9e3ec8b384d0eaa143f69593400261ad9bcb746d9be5dd613118b6448
+    bb31af3207c2cabea82345be05be7fdf5198225ca65e71ed;
+  ef66f5306ceb0c6b08ac8b0a22260c571b4a42bb
+    ""
+    ""
+    ""
+    ""
+    9f2973f4e855065a8d48db995fb178a141518b2737ac40d3;
+  8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5f
+    e8
+    ""
+    ""
+    ""
+    44295827bbc06d0fd366f80689343bff188759f2cd39683c;
+  368131115c037ba323fe1dc8151784873f0eb5b6
+    ""
+    47
+    ""
+    ""
+    bc4ca9743e53d5cc9fae593892c0ce36d6a7d08547cfe2ed;
+  da6794c18b5337685a96ed65b9aca338527ef19b
+    ""
+    ""
+    09
+    7c
+    dec701d10c4fdb386ca3d6546339bc1f896eaf2ab62fcc63;
+  c063c46f88de9fd41e72d7b97e23e6eabdff3bcd
+    211499268878dbf30f1dad89d4b9b12012e4713df4679563
+    0e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e3
+    9815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb
+    0d0020cb99818864e1a42510c9f02fa9d8e1b7eeece9e2a47aee82a256d573aa3b4fc5e71b7bb3c728e738eb84efe398a767378611a9c567ddd1f2d1dde0542273f61eb745d20483
+    2370d3c0afd70bc36b3bf48b066e6a669bb6421d7c96f5a3;
+  70e27e98ef1f0446b42fb144d44b6d00f06dc188
+    d472a784e0c6f21195a3b9f4ae985511265febd11c1647
+    20eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa0
+    89c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    8c2e22689dfa878356ce69e873da970dfdacb405aab70851448ceb62ba02cb110d425683508f8575dda4f95545df5db12e04bffcf5b81c5b83a4ba6e5dffa6421f513791b59152f2e102afefe2
+    3e1b8d85bd6ac24ef82725ef0240e33f237223e26aff80ee;
+  945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f
+    ""
+    ""
+    ""
+    ""
+    75e5558c9504d6207f55489f4884c98abb6e0beec7a95435;
+  0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1
+    c4
+    ""
+    ""
+    ""
+    e39471f2d0b80ffcb2dbd929c96ae456486b7d8b3f11876e;
+  c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b5
+    ""
+    3b
+    ""
+    ""
+    6b3580a5ea32ba95c99712d167ca737628592fea8e2e2b99;
+  f8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b
+    ""
+    ""
+    70
+    01
+    124d761a70529ba540c4a3fdc8f027dbb1795a730ad5e11a;
+  e04c091d205cdad9e9a79b1abf91b0851e5ca605ac84513995870116
+    77508a15dde524af3e2bee0646541a42c2ecccb44d65bad3
+    97abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294
+    a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7
+    9f006d1fa01a0740b164f5e4c14a110cf20206a44206cd847498c555a495fb07fbb62f35082ec3303cc08298c364656b41c741318162786b2fe494e6cde8b670e64ef492de01027f
+    712accd8ada4c4492c6fa2357c801ea07cb16b55179e2a5d;
+  abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bb
+    c8c6254d980398bd94e66eb4563d405e51881e99027b8a
+    b9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ff
+    aa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4
+    7a12401a5a74a3791b3fea7958393230536885a7761e3716e36c2b571bf9510dc268dd30a4faded0794addc797a0661b6d485a4ed2c50ecefd4932e615ab6cc4c9180bcd5491541475508f873d
+    22a1b541c2b7a784bcaaf00680273feb1a93c187e601413a;
+  fa8fec816ac861a8b33779f0
+    ""
+    ""
+    ""
+    ""
+    e78606fd15a8ba1222d2f85ece0d3a66618ad8308820fdc9;
+  9e7a10fc02a8f48afa3080ee
+    11
+    ""
+    ""
+    ""
+    2a1684ea67082c34418df0f0d2366cfc1080b493930feaec;
+  9a52a9a817e4f2b94b0820ca
+    ""
+    b3
+    ""
+    ""
+    83c2f7ecef5d874db22c51272440484a8fcd0b3beb84761c;
+  83a8cffeea7c486315799dc8
+    ""
+    ""
+    75
+    1c
+    1d96631473b4223491a78b3e90f91223dff32d90811433d3;
+  fba578c8ec4837898a92142b
+    5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d
+    14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0
+    e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877d
+    7daf1f5c982d561f22d520d3a528bdc16ea98a48c641b6314b0cd5c6da05f6bc6f3519be0a2c81177e44de266afa4f62b72d9c2800c039115ab81b671d940e314f1edaabe7685aec
+    e7d163d20f75659b4b0fa2b150abfabd0e1a83a4d5903a20;
+  e69146acc3ab6cf8556b7aa7
+    76945948d1b8834df2196c92ec1718dcdeee0d52d95397
+    26d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b
+    04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c
+    f2a5115aa965c209277a24b0c325ce806520f4725aba623a5edd757c9b8ae4da2f4e918ceb2ba756bea2b7e16ce28cd808151ff29ea78c662ddaf739313c5930e2859da808369301b81db91309
+    77613f8246951823e51a3370da0344a58531540bafeded71;
+}
+
+rijndael192-gcm {
+  60d7bcda163547d348b7551195e77022
+    ""
+    ""
+    ""
+    ""
+    015da0e6189d029fc8dafe862408dcabc30fda92fc68e1ad;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    ""
+    ""
+    ""
+    c932ffe01a259789c15ce089d5f8b7ea68f802ad4f95d278;
+  8f86edd1dc9268eeee533285a6ed810c
+    ""
+    9b
+    ""
+    ""
+    f00e7ec01693132f470761f98c38f8059d68abf0f24619cc;
+  689daaa9060d2d4b6003062365b0a543
+    ""
+    ""
+    64
+    10
+    fe5372d9b2db602ba2611ebc0100bce5c00bbed04792cb05;
+  c76c160f11896c4794846ecfa14a7130
+    c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd
+    739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff
+    61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde
+    c59a7b60e5c4237f3c10e9cde0219aa4099ef7c0323b9b6a2b9c403327510e8966c95884af2892e93562b24c97711b08dcd6d3f96cd6ef4a4965ea599ce6483cc8cc7b356ed79aa4
+    5ce6dffcc1adf4308013c22d19323d83025c0f821b25bf4e;
+  52ebfda19d0ccc520f215eb57bb3a4f3
+    ebbbb18ac6c95a97a48030370c33d090c54215ab
+    d6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff
+    63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77
+    c82c8f3a0ce6dcaefdb53e2e831e9192559ce8c45c1967f5a9ef2f3ec68b94c9c2206a606c318d53ffe10e195a5d3ad88a866976d18550e9e13e6d3df6954b675eda0b433bc4bf78a46eb25038c4c1e1a6
+    e2203c3246cd4609749431f291149ec7359c6c1f98316738;
+  dba189196d1ebba10b0467cb9fc2712a
+    199e533fa9156308cdec3f768281e040a9b9a222bd689a
+    ef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b
+    5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f0
+    e4e1aa2a9dc0ecadfab0d06a51cc52bc051eece169d640ea09e5ecbc5132389d823bf160bc0c3fd935be0a07b7350bf34aae3a6e93aa874aa8df85949f3ffce3ad63b63d972067f2ffb42da610
+    033ee0ffd59a68e6c64bcf376e1b4b5c3b55b704af3efd30;
+  83455b663e4ee1315f3c8f2aebfa921451dcd1af
+    ""
+    ""
+    ""
+    ""
+    11162ce42451687d06c7ea1d05f235a12f8c1dec59f7ffb9;
+  5813b70d30ce2f1fef6ef315d0798391805da08d
+    a3
+    ""
+    ""
+    ""
+    c9f80fcab02986639b9e1f4240582daf41b51a065bc6638b;
+  aefc5f8584b7c5e617669c0f16e39815d4e9cfce
+    ""
+    3e
+    ""
+    ""
+    64f584488df21b4e6a7cb5b54551516ed0585564f2605551;
+  d1ecdf3d264a7f16cb16c2e815f422cdf0c8e303
+    ""
+    ""
+    08
+    93
+    9dd3171ccac6312ff23949e0145b1f20c157eb70c7a100cf;
+  be3c31e6bc58c0b7cadcb658b970e47479a684b5
+    aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb
+    70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0c
+    fa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456
+    2aa894b96eb2a06a0c601e1f32a5495741e7cd0d98ade2e22742931a96e86b1620f6bf3dc60e865f24029760aaac639a9628575a224c48cabb0b207a8c646da177f0180a9484003b
+    09e91a6ca2951ac43b2dc376bfb2459f9d6793f3fa6f19b0;
+  f3ff669c732b58db8f48af65f7cc9e3fb90e1721
+    b730374ffc9bc597f56ccbb2f294b38766fc69f6
+    a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a125
+    8b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16
+    2a34e82df940e666655df615cd9499c3f0cbcb42d214c38a86130abd270c3f2a1aeb290e30d3aa4ff7e5386ebe20a7140c329e02f8e79ae908e55b44b32201191c1061d525d815983d8a413460155e66a4
+    62d2e5ef4662b6a369d06431d0b42ad0e89280500ba3eba1;
+  687b7bb8deb9bd205b70e04c091d205cdad9e9a7
+    9b1abf91b0851e5ca605ac8451399587011677508a15dd
+    e524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd250141
+    07c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e
+    a5d9d4f2cfeaa5003728d73631498986caf5ecd07f21be526aaf0ba42f4e94ea4601b93fd94d3cba101bfd9f4092d31c37a787d481bcf6e0327ec520952a55bae4cfdff57b0b5aae071e182b89
+    bff9d687d796f186e930b3d45a7ef9da7cb6309fece26936;
+  6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe2
+    ""
+    ""
+    ""
+    ""
+    20e8e27fd32514b1b14272c20f0df7247f31f1f4a12f25fc;
+  2d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94
+    e6
+    ""
+    ""
+    ""
+    ada7ffde4179f00a0efa887dc253ca41f00c318ed87aa2ee;
+  6eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c
+    ""
+    5f
+    ""
+    ""
+    378e18a38eba655e06b6f1e4d453e0afbdecb51191f33822;
+  87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214
+    ""
+    ""
+    e9
+    7e
+    ab0bb740c0dc8e10d72db5f5d9340a7f3f58205422105151;
+  ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d96
+    45563a308ba60076817523bd2abf1261b089d8f23a9c2835
+    076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee11
+    9a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a43
+    3f01e886e13d4af838c1a081adb8940ef6f24dabe3bd968a1c256dd08fc8c2aef84f7c389d6049f553750678d40e05e73c272540a02ae22d37e3ea42b38b7b659661fda031256ac8
+    4e5447fbd4d6ae6b948968a3944daafb7dbfb2298afa517e;
+  a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab
+    1eaadf66fd22ac1976063e113ab61f813e28a139
+    7a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffd
+    c2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df219
+    0ce0e6e23e9b00a1925b4704d89f9ddc27e6184940419c3f4755b3a268f8ca0cefd898853791b75c9dfc09f72d8e3f1e76b68a7298131a24c15670b0f29150356b1dbb8281d2168fe870d5c2b13c7d515b
+    fc65f244ef465fab581fe151522e12881796968a24ec9f9c;
+  6c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08c
+    e7cee4758a386a9943e97dedfbe61e737882cd09c2b9a8
+    0f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c
+    3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330
+    c9e1cff17ba016005ee6bd63700c2d80ed5281dd7ccd14d19514e1a0ec2a2134d9bef71d92a8bb3c71c0d4622800300d21d16cd076593c492361e2a849e71f7e51d9d6fff53b61bba0e19fb25e
+    44aa54e465e68d39194421556344aea25bdc16f0a24c0685;
+  c43f3df6c2b3fac7cbcf9652
+    ""
+    ""
+    ""
+    ""
+    ae9a5d3998de53f84bca8beed16dac8064c3ea73d0c67765;
+  3d4723f91801325eb8553236
+    65
+    ""
+    ""
+    ""
+    f062371cf3f7082c2e21c136112bc6dd3eb3b455a5624800;
+  1c96788d73d192ee53b3f3eb
+    ""
+    d6
+    ""
+    ""
+    05013633667c00adb73c6442909065b53d12eb94db18480c;
+  6ddd98cedbe88e245de25b15
+    ""
+    ""
+    93
+    c6
+    78adfa0aabbe6558983554b3e73782cadcf950c21f27ee67;
+  b70f8601562d90a9b59ed034
+    a867642d25d54756fa5c47f16f64b837bb4926214211a1c6
+    96ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed
+    6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825
+    da005542936f792bc7fed255ba5d8c04b90fa64185338a24a954b79a7d05252230a1167ef6eb35d1281c1927ffab7b5c714321e03a01274c3bd3583e3ec84f7c56d60000e18242f7
+    2ed230cfba9714d0d3d35df936ec750a695fccd25539b46b;
+  ecd75a66d88eedb969ffe076
+    69845ebb7a24c69f13d099f47166edf54538e88f
+    bf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da0
+    5780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2367f04
+    85ed87687fca97cdf0ccfe1d4e0fbdd56e674a6ef5ebcbc4979f80e6f8ebdc85672d01db63bef05103c1327baa49d7e6e12854ce3680f52bde86c075ff5df02daf0db3e48b564a804cb3b657f982a27ff3
+    e37d522450d16ff30f15ffa74a0b894bfd33074c4ea06f44;
+  7265264e0da72efe8995e6c9
+    32a17eab511eddb8e4ba463c663035a6ae8a7a899e4279
+    d54d03f0e0f3e961dcfd40088d5be74088e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d907eab7707ca48ff5ba1ae93d16225d469de57
+    47bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd1
+    0b9e340c141493f9676c99eaa36b0463639b3db40dce5e2bb48c3222a1b82595be0ae12890f61bdc22f71a07b8ad0136d395221c57e12ca7f8184d3adbf82497f5c6ac105b1545d433a9baf50f
+    b24035d9900bc75dc879617502f0f9891a2428fa9d6d472d;
+}
+
+rijndael192-ocb1 {
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268
+    ""
+    ""
+    ""
+    13b24e23a3819cb4d7bf3ca036241de7b3420a061b6d62d3;
+  eeee533285a6ed810c9b689daaa9060d
+    2d4b6003062365b0a54364c76c160f11896c4794846ecfa1
+    4a
+    ""
+    ""
+    cdea5e7be1867fe4017045e85df90d80eab16117019cb8d6;
+  7130c9f137120634c9519848a877ff77
+    bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba
+    ""
+    23
+    82
+    b32646848740cec0d5c5a20e2d56c34d455d9574159fc509;
+  4085406a6136512061f7080cc07df059
+    1d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c926
+    ""
+    9029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b00
+    5f7a353fa6c23af6ae6afcd8fae5637d8ac4edb01faa216d94a8b31628140de88e741c1acd085a5e98d64f69090556f641d8f1c813fb1b3675a35aad57f6f48ebb0b7a8270df4216
+    76df452b066d18894a564d78abd6d0c649602bc325f73595;
+  0961040ef2f9b2fc5fa450727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a
+    97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600
+    157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa91563
+    6ed78c4004e5960f34017f9272ef3f237d5fd83076668683183dbc0b62201d1223550af95841dc4ac72f0bc0ce36f014237d026518a6b1bd0ce01e56e87bfa9c42f4651365f65b8c
+    dbfa943531e52ab36828c47f5e21fb22ea0452f0a45395ac;
+  08cdec3f768281e040a9b9a222bd689a
+    ef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233b
+    ""
+    fa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff
+    74751fe7898b6a9c7e28c4e3132fccaf4b9af8ceb80ceebc88672c05c49d5286724ddc6bd3dee79921cdf0a0265277d43048c588e5d707488d1dfd90808d6b74337d1e88aac9618ddf181c1653
+    dd9c6625bb9d22266087655b51efc0a2d8cb642f6c40c6d7;
+  3bcd211499268878dbf30f1dad89d4b9
+    b12012e4713df46795630e7952d22bb02d7100b8b649377d
+    20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ec
+    df3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b
+    bfecbe5ee869f7c5b4bcc3282963ed6dae5755c25a070c40b4d6a8dfb74670bc440d0af7abc018642d36a946d8488aaab9eabc0c7cf4ec6d2f8a9a738c131188af47d7e791c3f7e6a34d26724d
+    5dfee1b1d0a1ebd94737ef267a755fddd2092bfd35e7a238;
+  6d00f06dc188d472a784e0c6f21195a3b9f4ae98
+    5511265febd11c164720eef9eb1c8dd0b00951f284649016
+    ""
+    ""
+    ""
+    6c1ae06b473969bf8d4abf8890f91ccba11f094b316d82cf;
+  ed00456331854bc78bf43966eb0cfa9138ddc399
+    08445608fe95e81c2533e31c9c1a9851bc2810d858cbbc84
+    24
+    ""
+    ""
+    7025cfe14177506ac341239746234c80533c6fac1b94afd8;
+  d126b807e6daa089c3f9099c5ffb824173d7634c
+    04226f30cbb7f0e4a973a8cd190107314717a77456f3ff66
+    ""
+    9c
+    f2
+    91c9a9506104ca20249008a5210a18e972aa0865d8c083c7;
+  732b58db8f48af65f7cc9e3fb90e1721b730374f
+    fc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd5050
+    ""
+    03cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3
+    5c8a44ab82a0c2efc66e6e039e7c70a611991b5901b7578c55f4716fb7bd37f55c4bdc962f7f1ed93e14804b4d41695d639b3b5b1725c9129a47ae9542d11787064051cffca20611
+    acb050737b017b0b4c10a120a4d740a2ef33d5e26e7251bf;
+  a4c84cef64f6c9b53bf8f957f4b03cf43e89957f
+    9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205c
+    dad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc
+    338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70
+    77b5382bf3a2e0f3545f398ec08d94825572da0ec6bee8d16a98d42f246eaaa8d049499dcbb872e5d751e700b3d2edff7264c1eaf2f0a0c8987932a53e171e62c2364212f3ef3405
+    87c558d944a7c325965931188213f6a37719581ade0d0561;
+  d17d4569eaff59a332ba58d5d5589bfe079753ee
+    1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6
+    ""
+    dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de128
+    0f50a0d3b7e41c19a9ed4c679ae42b4ba5055d3e9c60652c07daa390cea5c499787ffd7dbb1cdcfe095ac7549db82c3068e053bb2fe3fd8a5749d653be84a5ffadbc1dcfa6a400006f6badaa62
+    14270e56d692e540aa7cb92b1b285eaf00c6e183c6f03341;
+  8c69d80ea12ff4bb5f069b8a2e86041c1b9fc214
+    e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa
+    6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33
+    958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1a
+    d9933fb77ae951691f9b11b7eb9a949191c1a39d09e4bc78a0be75bc8c101ad281eff87a1f5da724d79235e949a589b39125d0a91025a9e126054d980307b934a590687c64e457991a88895367
+    03e5dddeb49ab69f6a062242f8c1a0d1d2efb55895e03a83;
+  c273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae475f6b94a
+    43a67b3d380d2f9aaafe2dd721c0095c8808847689211450
+    ""
+    ""
+    ""
+    ccc44a234758478dbf8787d423d646f61b0cda1598fca3bc;
+  ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974
+    a1d7f4220c785fe426a5a0e80f678d404147842941feeffd
+    c2
+    ""
+    ""
+    49e97ec66094c4bc5ab035aeaf6cc43dacae0f582021e584;
+  eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e51506
+    86d2301b43a15a84e81d7f5cedaa49e2414ebf47970e5604
+    ""
+    75
+    48
+    8128cb7db1a943e0cca309d9204164fbd9c34ca6c07f784c;
+  cff206877de69146acc3ab6cf8556b7aa776945948d1b8834df2196c
+    92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07a
+    ""
+    e8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b0739
+    f8e281d776b2fe8726809be7abdd62c22c4b523b7613a5858be2a07021ed3dee1945f62bb37cc0be1de3b1e475ed5828ba13a26f34e2651da980ca02602c5e58c8834ba9e8cb5e5d
+    97fb24449e5402189c30187aedf9627577f0397158331735;
+  8a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef616
+    14c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de7
+    4fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c
+    96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22
+    bcfa139e6fdf6e5bcf96a5c29f8e0145c1d613edd25b9653bf6772d21bc6ae69fa71eae2029716605cf398247b7f2e5a97c5886d94fd674c40b5d42218c2adc7f84770e7288fab36
+    c92aa7646695a597df47a2c686ba2abe2b0d20caa4052185;
+  d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b
+    1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839e
+    ""
+    a59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8b
+    2cc3069cc00db4c51fb54ccb6ed44217a5169eeba4d3fae16878af2b0f969d5ed42da3fe8901645369768e0ca33cdec8cd422a0442c798d8a214fdbec4564b09d70666884ced9a0e64bc9eb3d5
+    d9a32a67db1fefa016cd7961df3e0a9e9949168242a2181a;
+  fae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f4
+    7166edf54538e88fbf433a7ff212085179e79771f6eee728
+    3ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e3
+    4c8b15ad930c1b627235a2cb84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088
+    c077af8264ca4bd0902dfe7c6f43dc4232c619bae8d151f9be98caf39527e373efec0dc9fa55b62f207b533724b78935255a608e9ac32da258e8f4549d473b95b9057900b2f715425d19804801
+    125a60f3f7f0913f203632d93f4f2cc70e76ca59cfda9a57;
+  e4097efb0368c7e2f431ee69
+    88cf2a0e9ebeb3de79c4f86c9e4fba61339d6d907eab7707
+    ""
+    ""
+    ""
+    d040e427a7ea51019b49c65a9c38a803bdffe3635357b8e3;
+  ca48ff5ba1ae93d16225d469
+    de5747bc1addf5748729720a320fe14fd29cfc59314fe207
+    9c
+    ""
+    ""
+    2bd8090e45ccb18c92e3c133a19e0a3d3bca6dcdc4f5d591;
+  0a2535ded56112d6e3d33dcf
+    7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac
+    ""
+    71
+    fb
+    bdb4cda8932cacfa59b5e1635a394ffae6a03ba034759e86;
+  e554a6850d55882f8c7ae699
+    4fc8528bd18c374fc43581d2f72a89584a2404a059f7f99c
+    ""
+    7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd651477cd726d6f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94
+    b29f37bc84835d3cead667fda5bcaef6a0b93a0e1e79169f94d0111d28e0374fe7cc4a2f9ac274c3f31121d2a1058094b6ac1707f92c87a45301cc2451eebd8501d63a8f561d2f86
+    40f807380b82f25a620597ef741e74638ccb5a7a58e4bad4;
+  bb42f45a8733b2cd2df9d1d9
+    05cfdb29983050d6bcdb686a0c897031ad09a5b8fa687ec3
+    bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b612ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c839839c1b06319f687d
+    bc68d9f07fd41ccb4f8cde8de201ec2680332bbded4883deea0b58b54bdd13c17ef292b0ded3caeb5e57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1
+    d3445b37b2ee6f261baf94fd09ba0121b1ef9a8dacddacff5ed3bf46c36cfd1f2a5e9a1e35b73299bd31137a2a7746c8b46eeda7fec1662842934d0d1b41d240a40886e17f3733d1
+    2f65d5e606ea39bd566246b137733278aa2942ace8edc2fb;
+  b9511bd332c86e67f123377a
+    8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64
+    ""
+    d492d39ea7496993a25b072945d83f923e66b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee7
+    65bb74fac682e5422c376f255b91a383334486c836f5f5d578b276ef240206a1761e2dc66109d2b11c4b2d25411c5e0a86316501a1a22a779ed2be816b7b84ebbf1c0cbb41a332dcc43a8d0912
+    0023df18856b33924dbab9d86440a7fd289d314aa17a282c;
+  8ddd9236beec76d55ed58b10
+    f91d07a037791ab96e83c4bf2fb5b205e592c172a5cbc194
+    56c95c1bea6079f3867e52d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f23564672e370ffc37d400a31e8aac1d426ce10df73c5ee478b3b63d
+    91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6de738721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d93d1f8fcc53574427767396322b3bf7d02cec0509
+    b58b1c9dc465be8b7159c9f7c4b8ce39c251d39792eda3da5be8ef7b887114bc1b5af143be79983b37a11a0d96082c924d0308999a39734d0d6eee63e651be9a2cb1cb2fc8aa6db22bb146ee53
+    210b175366af46c07715847dfd494cbad171f2d8ea711f9c;
+}
+
+rijndael192-pmac1 {
+  60d7bcda163547d348b7551195e77022
+    ""
+    a2de3f1a78f51e79b270024ef181a3c7866c4901882d8f2b;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    a69a6414d3476b1fe006cd01597794cdd6f335aa776941db;
+  8f86edd1dc9268eeee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba
+    8cadcc0f2b6f103713f1875836da1fec0d2492e592969018;
+  234085406a6136512061f7080cc07df0
+    591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49
+    5fb116908156463f1b1f698e9cecf1e6ba99c5292359e8ce;
+  ae1d50c38201a894476b3f102b752eb952953396
+    ""
+    9590db354fa1be8edc4f4464d0e292ddc6c38614cd7a8d9f;
+  6f27043eb621b7f65b000961040ef2f9b2fc5fa4
+    50
+    d4354854bd0f842a2d7d2d1ba28362a1ceea024ee706eb41;
+  727a9b542cde52ebfda19d0ccc520f215eb57bb3
+    a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f
+    979f0fbf31f2afcafed5d59414bbbc8629c5c1451ca52f3b;
+  8f28523c03d4de1600157846b710ee72807a2219
+    bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f7682
+    9b980aca9bdbb8333cacfd8a76c8bd57e1862136831e194a;
+  81e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a
+    ""
+    2e46bc43892089f8eba2108812c2cc5c4ec74ae390223bac;
+  42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c
+    03
+    e7cf293a42d599e87773781f8abd4a303f2967de3a36b17b;
+  7ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9
+    aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b
+    c190a80eb16dea538d732bad5c1d06decbc09ee1a4eee891;
+  663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef3
+    15d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e4
+    54fde6333577613aebc01d5de58556aec8dc6911983a136f;
+  7479a684b5aefa69a4cd5214
+    ""
+    1d0a9120f17311d23b4babcdb18d1225ec90fa3276f35054;
+  7ed12ca986981a874498ad0a
+    be
+    34750cd4fc57273de4b5858c39bf05da2b0156496adec2b3;
+  f8bc4fcb70e27e98ef1f0446
+    b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc3990844
+    22e6ac9f6fa50e49f0e24e710d62c83fdb6ade50f102bc31;
+  5608fe95e81c2533e31c9c1a
+    9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e
+    d3653df2ff5ca70439d6f154551ba9ff27c5ead8db7af2a9;
+}
+
+rijndael192-ocb3 {
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc
+    ""
+    ""
+    ""
+    b5d14574dad19385409d38eddbeb6afe08cbc6e40260f7c4;
+  9268eeee533285a6ed810c9b689daaa9
+    060d2d4b6003062365b0a54364c76c160f11896c4794
+    84
+    ""
+    ""
+    ff39389f60d0cb58841212408f59c1313e57029630808bbb;
+  6ecfa14a7130c9f137120634c9519848
+    a877ff77bf79192a5b50ade5d9cd739a3d1f337f2954
+    ""
+    9e
+    bc
+    af0809f4d9e7b23e1b98f8b65fd7326aa8b546065218757e;
+  6b0d27a4ba234085406a6136512061f7
+    080cc07df0591d8fa21f2dd88374d8cde8e160
+    ""
+    ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    0fd527536eda95bc7b5e1e67c5737626da7251fb0bb540e3a684656d29c7ee45e19d670d8c7a8a896633608aedb539b5e42d5d9d8d05320777dac9687207f733f137f64a36940ffc
+    e8df4fd3fac5b4b10a2242cc5ddf436f8acac68e0700dffb;
+  966f27043eb621b7f65b000961040ef2
+    f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f
+    215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b9458630
+    6fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b
+    715f3c2b119bc11bd4723df66915752c925e89e5652090168877845f6a5cf40c032b3a54887cf0cbae47edd7623c876a2e3c2035d0dacd42a8820bbd7a20d4991b3c8a98ad7d8331
+    1b8c5703782c163b28509cb1cb67e2e0bdaf949867dc63d4;
+  0467cb9fc2712a199e533fa9156308cd
+    ec3f768281e040a9b9a222bd689aef66f5306ceb0c6b
+    ""
+    08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063
+    fe808b32e6844a1ae334b145183e092c6c18eec5268104868889f5e9f197a831ebea245adb9ead21c16461918a5b48f33720884758d98a55380fb9c088c60a120402a336a646f2499d44e59e44
+    455d8abc815b66b77c0c7b048215508a1420d501c6caffb3;
+  c46f88de9fd41e72d7b97e23e6eabdff
+    3bcd211499268878dbf30f1dad89d4b9b12012e4713d
+    f46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584
+    b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abe
+    1c8d47ef199e6fb28c25a07ae8051b0785c73579e224b9e85990c66628a3e2a1f21e26735a47c3df4563c23c0e2814fa708566948113cca1fddecf2109c56dacd260689b45c72cedc522b593c8
+    652c3473b278ac660297c275b0a7beb9501c0d8654310b3f;
+  f8bc4fcb70e27e98ef1f0446b42fb144d44b6d00
+    f06dc188d472a784e0c6f21195a3b9f4ae985511265f
+    ""
+    ""
+    ""
+    b0b54530145be3e9ba77f97799d7a386747f260b20c71d4c;
+  ebd11c164720eef9eb1c8dd0b00951f284649016
+    ed00456331854bc78bf43966eb0cfa9138ddc3990844
+    56
+    ""
+    ""
+    a7544f3687f32006a57591900a0a73224133ccea2e6c705d;
+  08fe95e81c2533e31c9c1a9851bc2810d858cbbc
+    8424d126b807e6daa089c3f9099c5ffb824173d7634c
+    ""
+    04
+    7e
+    13f61abd0de5586dc8a054920b885d81a075db59807b3de0;
+  226f30cbb7f0e4a973a8cd190107314717a77456
+    f3ff669c732b58db8f48af65f7cc9e3fb90e17
+    ""
+    21b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554ac
+    f67230d596aba65ecb5d1708bf3eea0c2b8adf346fdb033f4c6dbc9e1b1a394353d4d054ceecf6cc9fd93487da8a5c70feadd5067c9b20dd5096418c2b1d96de1c24ffd51d6c376f
+    4e72953575d116de1f5283af168f6c9e93abd250d36e966c;
+  f1270485b203a3c1c4c967c0a458cb948bdd409b
+    687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957
+    f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ec
+    ccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d98351
+    ee2b2fc312e954332969db113f066c2ca26a2a521308ed891cae549afdc3198d1c1e154c73a675cc74e893c95a0e52473ffc15b5540339b3b3a5e62bd36be0e08c5d313d2a1e8cf1
+    a7001eb1a36d838c1425c07ba29c9f8914094e5cad71bbf4;
+  4605ec590294a319b9802068a9f891bc5ba5afab
+    f8c3122d12d7ff3c41122d70d17d4569eaff59a332ba
+    ""
+    58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb456
+    1411b2dc14e6fa752fa2092a36657ebf4e742ad3f74267c6804dd6e9b508c526639d7ade46a49af597966bd5c4cb83ca831f638214498d700b7b52512e7d1fdb1e2e4443d5f2e110901730461c
+    eee75d53b2357e78a5b5aaea134f60f48bcc4a6d0f5c8998;
+  3d405e51881e99027b8ab9aea3ccf860b0009740
+    763d96836c5f87b95460938de1288c69d80ea12ff4bb
+    5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a
+    23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2
+    c4a9eeb3f04799ce6944e8104509fa1aef8f17b5815ba391c356d895d7cf996513eed08a74f58e01e534f0f5c3079c770e255a9278fbe8a3da967a01d5536b1a87292db733862f4f98304a7307
+    0dbf831632cb781a3ec5c78d99e363ff3e7dfa646fd9e90c;
+  b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a
+    92142b5b0677da1ac273117b45bcfff5d5f8b6fde289
+    ""
+    ""
+    ""
+    ed4dee5d2f4f878178ede9ff462515501765dd09987f4957;
+  3232a9f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0
+    095c8808847689211450ba8095ffab1eaadf66fd22ac
+    19
+    ""
+    ""
+    2157ffb54f20ad64b0ae17d72c99dcc7f14093b49121bb30;
+  76063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f
+    678d404147842941feeffdc2eb44dc8c0d5e8f444f7f
+    ""
+    4e
+    b8
+    0f3e95269af57fd63b09cac38f5c5f0934a752201dff056b;
+  0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f
+    5cedaa49e2414ebf47970e560475cff206877d
+    ""
+    e69146acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9
+    60b0cded984a7111026de06190745d65af6942a64b7561ae21f68d213ad0ad22ac6fe56c8b7dd756cd9bf6ba13c2c011cd99387ebae0422a4e12e11ceafb0292de2097a876e5c416
+    b28761e6f95f1faef3e4203ed6bc359c0406982b19d8a6d0;
+  a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9
+    ad5b04140d98edabe08485290a4d87d13b07398a14
+    58c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7
+    cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de2
+    76214c8de16aa91bb77876d7975b49cc15da1a63487133994bda609099c60d7f0d2bbb2efd5af7dc3a276a56220004edc7b1da45c6164d91d77772ed91d587b9caadd20e27d078db
+    38e894b028899b17056bc987b2ba8fbd7cd6d0cc4a50fb38;
+  5b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f
+    64b837bb4926214211a1c696ba172010abb433922a22
+    ""
+    d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e
+    c84c85f543c7f56134b2b5e0a48c384ee52d231d0706b2524d39cad86d4e02c085d3c95f96e0e4bb5189376b5276d0a7bdf6b554d92c8984168596abebea609707fad78cd0ebfd0968823854f2
+    04a3929311c62ac5a52e41328632178462d078e4a495a115;
+  2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f93
+    8f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c9
+    4b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780
+    ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be236
+    7f46b1b9de6077c8ec8d7a07c53c4efe4a7fc60cb8de683164df9faf4b4bd540b6076f4f8449f215ebcb17f73ad9d2d92930e0134be8a56fca74f0f945100425438085e7b3994752a100db09d7
+    8465609210664b702ba7297e945027461069d9dab09c8ada;
+  7f047265264e0da72efe8995
+    e6c932a17eab511eddb8e4ba463c663035a6ae8a7a89
+    ""
+    ""
+    ""
+    867ef0e4e4136a82e85c2ac3a7d6caa7a0c4789af22df032;
+  9e4279d54d03f0e0f3e961dc
+    fd40088d5be74088e4097efb0368c7e2f431ee6988cf
+    2a
+    ""
+    ""
+    9d88b7a1abb6dbaa577fb9032334094d426045ac2b848598;
+  0e9ebeb3de79c4f86c9e4fba
+    61339d6d907eab7707ca48ff5ba1ae93d16225d469de
+    ""
+    57
+    eb
+    af67bb55608d1620c17ca5404cd788d4eb6c738d9597fd13;
+  47bc1addf5748729720a320f
+    e14fd29cfc59314fe2079c0a2535ded56112d6
+    ""
+    e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4
+    d72178266c9c112c4618e31aa17d1b48ccb51963204539bb07ef387a95454f43c4131e65c1fc4cc28ce70666995d4c86b69f4031edd9abe6e71b27270d75e6c786282401e38bcce4
+    a9b01accbdfccd6b65c684d04a9c836de6b7377c93f066b4;
+  455b382a9ce757b3e7a1d075
+    85ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02ab
+    d651477cd726d6f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a8733b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad09a5b8fa687ec3bad8e18d
+    c2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b612ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c839839c1b06319f687dbc68d9f0
+    598a1235709ceae2308d4c08c0bb6019a8797608d983e6701893d983b7574662a7790da0d68b07299907272fe218cbd19549cc10b1aee2f70c23b1825f734c222369929d78780ed8
+    f8998bcc33440204eb8abe0ae0a50dfc6d59eac76ea51cf6;
+  7fd41ccb4f8cde8de201ec26
+    80332bbded4883deea0b58b54bdd13c17ef292b0ded3
+    ""
+    caeb5e57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea74969
+    d66d4a577c1df9ddc37036d5ba8206a6ae9b59bd7d9f096c4184be067aa8c6f836251fd1187edeca358a375cad0bd2ab89563978941870552c94faf821971f77c1583e51fd5077f32b9b5bfd0f
+    1f839690aead572ae9fd15ee968983dd34fb8dbd4e5827be;
+  93a25b072945d83f923e66b0
+    a6689cf0969c003a8fca80e322a4b1bf050c12204504
+    33efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee78ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592c1
+    72a5cbc19456c95c1bea6079f3867e52d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f23564672e370ffc37d400a31e8aac1d426ce10df73c5ee478b3b63d91024780e9
+    5ccb483f688309a92fdd49b62e82cd6eba809cc87085e08037d2ec45b51db4dee112b3733a650f1ef167d684e5fa46e62ebd7002433c0022874a5839bc57b13f41ac3d221d0ec3d6f727fd1a8f
+    ab66a6b01196d8dd216791da419b5cf132788abed4254d85;
+}
+
+rijndael192-ocb3-mct {
+  32 9f02c63dd249efeb7f4d8453ee3c38cfc9930a7ef42faf68;
+  28 abd57fc930c095eec2d8cc466a26ed96ee9b4ce00bc02b32;
+  24 ff3b3dd8e0f774136f01351375c53605687c0626f0456253;
+  20 c05ef316f4452a992aebedc3565760cd61dbc635db5b01b2;
+  16 3e89734e70fa99dbe1571178aa1edb917330932a2ff6ac64;
+  12 7506243a5da5b0cfccec7138bdd6139fe41407bbb5b410e1;
+   8 e6aad44d2d891651052c6b1386bb10b5fb782976df1c1e70;
+   4 6ddb5a25933d8061b4e5e77ec3cd10680308a5dcad517385;
+  32 906dddd0884c542b133dff61c61f2162e9d95b10;
+  28 33d3e253c75e411ceeee00c9a0210f7c712ecd66;
+  24 859cbce898522f5b8722d39fd102288559711820;
+  20 1d323ad20a20660b568279370228800d724d4c64;
+  16 7604277e9535634d8a43f77a051914760fba923f;
+  12 a144bd8fac2616e541c222cb1d8fa1937901dff8;
+   8 9e4c1fb5aabf111ecb49545a92dc91449345ec77;
+   4 b2a77eed505ca3ba5edc1a95cac166b02f7ca515;
+  32 52b3de9c9a0e7a7f3f65170a59a0a959;
+  28 925abc1d13cf9aa5c0fbcf73ac78b559;
+  24 08db50d58b2e97c2931e231775fbabae;
+  20 1c154b77e569e62ff13603a6397bf88b;
+  16 a514526ab5a5f5622632bf8dbb009f74;
+  12 1b483b245d9c11c1ad947a74f7303b27;
+   8 ec31ba263ee64ec9f0e4ff4d7a2498f3;
+   4 dcaee7b3276238b3d9c946ea970d823c;
+  32 f43eb7ac65b4f6cc7ef4c1ef;
+  28 ffdeff14896db787f8b9a8cc;
+  24 e3d0eec8426fb7223622eed6;
+  20 7b9b29ffe3f2de6b85b2f542;
+  16 4a5928e2406cf876486539d6;
+  12 e1a51d35431662bd48c8d4be;
+   8 3fcc5d9987661e00bbe41201;
+   4 c5a4cebe92b555fe8a3bdad7;
+  32 dce58465343f136e;
+  28 6ce50ed44f5d41f1;
+  24 876ecff3404f371b;
+  20 605b7adeef15c3f8;
+  16 a56e57ee9e8f5130;
+  12 48ebd3b98cbda23c;
+   8 c34363871760230a;
+   4 484de0d92485471c;
+}
index 732685f..803b2d6 100644 (file)
@@ -2895,3 +2895,931 @@ rijndael256 {
     1188d6578860ceb90a80228c344c3d9e72e775cae5d41b0fd9ff9c60d0898fd0
     ec81f1cda5409281c7b4d5f698b6ca5d0ec79598571237a08a60a4a0724b739a;
 }
+
+rijndael256-cmac {
+  60d7bcda163547d348b7551195e77022
+    ""
+    a45b5e26bf4b809a89993f34d7b96a1518383ae7a57b51c1ac78cb29a1432a2a;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    768cdb787a4de07dc2c7ff3c1846d2fbcd1bcf867dbe9f25607cca4443ee25b9;
+  8f86edd1dc9268eeee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd883
+    00c1e6af11c6d84eda40876c32f4467f45a0f9cbf862545bf05487fd06713dad;
+  74d8cde8e160ad10997a21635c6d62c9
+    269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52
+    8f1442e79bfd604a4400d183e4509b454411b03d63dfbae7db2b03c998db8724;
+  ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6
+    ""
+    66129452d7b724416120de9f272b2d531a1cc0faaf945ab3160734ae639483f0;
+  c95a97a48030370c33d090c54215abd6b3ad54ef
+    c9
+    1576f9e568d9bcb014a679b7024aae490080ba401d8808cd9e2b7fe57f0eab66;
+  a38378c5b93bf4f2aad2605faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2
+    e2ebc3f8e727de99c6fd46bef8e7df52599e0f8de53567bdfbfd2b52b907e7ff;
+  712a199e533fa9156308cdec3f768281e040a9b9
+    a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c4
+    afc6c9c54cbe70a0e7fa6146a5ed4ae9ce68a1d609af79708281be0c2715c8fe;
+  6f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad
+    ""
+    39733f351c3e4a5b686ff0a932407c4dc2f41bb387592881b3f92f915ece1cd0;
+  89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20
+    a8
+    b6caa7f9735ae9ea8083faa068dc284cd5d14332984ced7f46d3e93bddd7fac6;
+  f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f
+    1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abe
+    7fcf4a19556a8ba23df01de57087481a425410f3f092e4f801a681625b713935;
+  f8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784
+    e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c
+    6377ee34258253260374a4654c8bd727bdef4e5921e59a770a8a6178bc61620f;
+  5ffb824173d7634c04226f30
+    ""
+    4ad4651e26e46ac9b3890fc7adae23cbfcf808d96586a4c88a27c6a8533b51c3;
+  cbb7f0e4a973a8cd19010731
+    47
+    18566621f2c24c55bd880e8603461de80fcf01ceeda7bb7aedb4253204372e14;
+  17a77456f3ff669c732b58db
+    8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a4
+    16a524c850d351e451cd482587f4f622542283b085e16ba423c8c54085b08350;
+  58cb948bdd409b687fa3a682
+    7b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d
+    3e8977f205b75e6fae2105cbb8cdb26f3e8057957ce69b9e6be62362bd225924;
+}
+
+rijndael256-ccm {
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee53
+    ""
+    ""
+    ""
+    39e9b611;
+  3285a6ed810c9b689daaa9060d2d4b60
+    03062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137
+    12
+    ""
+    ""
+    2de43d0d;
+  0634c9519848a877ff77bf79192a5b50
+    ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a61365120
+    ""
+    61
+    af
+    8b7456f9;
+  f7080cc07df0591d8fa21f2dd88374d8
+    cde8e160ad10997a21635c6d62c9269029
+    df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f
+    215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a22
+    87e66fdcee4d517cac9c5df8c9a1250f9b4c4661766cc1f92ac99e539d615f16e9e922ed9a2858ec999c25a625c576360c99583babc0f0a2730dae7a28d505f72933cac1614ff406b2e57a81e42f6d939201ce863d146cea017de5759a440f99
+    c225cb11adf2da0fe435a56b3c32692e9b469cd9a3d596e980fd06753fae46e6;
+  19bfb474fd71d891f24bb65d1563259f
+    9eb53b571ea629c54d57dd2d42f70800df
+    9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c
+    037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b
+    c16a37dd487a042d5ef9f8e37dd62300e0f990b5d8b4475610726cc6c1f459079618a0e57a0c1a7edac73d37fc0b34772afc4db80db4b0955fcbe20cec2f09396f6b6935df5ba6a663eeda17386b5c2415a5ceba8da9f024d7ed0375d172cb64539a55c133
+    997e534457f57e31ac0bac767af4763e3289abe713dbe1b044dcd9d06e587077;
+  663e4ee1315f3c8f2aebfa921451dcd1af5813b7
+    0d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617
+    ""
+    ""
+    ""
+    c17f8532;
+  669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16
+    cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970
+    e4
+    ""
+    ""
+    9238fb01;
+  7479a684b5aefa69a4cd52147ed12ca986981a87
+    4498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06d
+    ""
+    c1
+    55
+    a72c2d2c;
+  88d472a784e0c6f21195a3b9f4ae985511265feb
+    d11c164720eef9eb1c8dd0b00951f28464
+    9016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db
+    8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a4
+    58aa01bd9e621d51a56834475abe47e312b92c5cbc9ba2bda0b6c93f8205dd034dc7ea07fff025df7357c96de86f1abb81b7acd50c8152c2cc0b858a1a2269ef527b5b29b58b365e85e6a0c86c38f84484dbdb52451e8b9f3045b87d027d4274
+    b0c5980dd1d865f66cf8afcab40eef4768d8eae4e3df3af89474ba26805dc97f;
+  58cb948bdd409b687fa3a6827b480aa3a4c84cef
+    64f6c9b53bf8f957f4b03cf43e89957f9a
+    3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90b
+    bf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6
+    d60e61dc2da592c48e916f6185dc2f21f8f81967a0606a90d65d2cd698eb7a496483fd545a49496f140faa6f9faa01ba37877b389f62827032b6f212f454415fe8b55511cbe76dd33304342e41def358962982d37f447e45ebdf80e1da9e971926bb261b8f
+    2d6f1893de28ec8fe81d627c746bef1734bdbf70342adf8366fd9ee123893f8b;
+  699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90
+    cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d9803
+    ""
+    ""
+    ""
+    d5c932ed;
+  98bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b000974076
+    3d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86
+    04
+    ""
+    ""
+    cc3630f9;
+  1c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ff
+    aa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a
+    ""
+    9c
+    a9
+    893c9eb6;
+  2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a0614
+    8f302c3973accd56f6f24e33958b8c2e23
+    52fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517ffae4
+    75f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959
+    696865f6691e1d423ef29c34769d153e154cf60958dca4671f95cd3e798b078ac5bb61ac610a204ae8fa705e0049e67e33524939589b79f2dd0a4afb1af3de3be22f63024fbeb4114fe9d63599cbb6bbeb46b6dfbff4c4c4045a195a9f6e841f
+    2f8b9f3db32f5ac54b01d587c12a62439f1c211ae0d95749c8c6307a53f94832;
+  b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49
+    e2414ebf47970e560475cff206877de691
+    46acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e
+    0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb
+    a6c5eba6167038a4cad7ba1d4b56486454220bbb137441c9dce2aeaeff28d7483ed42af4e09ada32dd9378f098f84a1490feb1b69fde424336de7ee13cf3d78e98b06d4c256ea7b2c8d09a844183d4fbd9ab8cb1e5daaa68065c654f913cf993f24352ea79
+    d12d64dd43380368b4c96be31ed6506d5062d06db2b9feddd8eeaab6e1e05328;
+  23841da1ae8f4ae480cda98a
+    d6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f9
+    ""
+    ""
+    ""
+    acf8fba1;
+  1801325eb8553236651c9678
+    8d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601
+    56
+    ""
+    ""
+    3ed65cbc;
+  2d90a9b59ed034a867642d25
+    d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433
+    ""
+    92
+    e3
+    1e19bf8c;
+  2a22d9fd881519165eb9d851
+    97a21cc34ac0d5ae7be8dbf98e4ffed2cf
+    6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3d1d2e3
+    1e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e7
+    0a55d15edec4262afac43ca1fe8e3d9ef79463234eaa45795af83c017e36d9238ccb373eb40a3eac59f2759558e25e60769170f0f38a433a24587c8c525db9af75cb4a3e91f0dd7cc0d59599eeb07761a35ccfa9c548b681e2353c743f60a4e4
+    9995e65234d6516ca613e75bf36b740df93c28e99cf02c5b1b9ac12479373025;
+  5079bb018ccc8c54f31b450e
+    88f8e9002926ad0284c738f4cb0f58a1e3
+    4c8b15ad930c1b627235a2cb84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088e4097efb0368c7e2f431ee6988cf
+    2a0e9ebeb3de79c4f86c9e4fba61339d6d907eab7707ca48ff5ba1ae93d16225d469de5747bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d
+    69a364a10ea53ab96e931e5c449427a40d2d571e8beb2dbb7577edd3c581456358be681655e7490b139a138ba9ffcf95636344a6886ae4e222f46ea7e5e6e4529c75276734895d322770de34b9919b2e7add2bfab0952d053b8991f39198ad4c61391d691e
+    77bab4bc3ed79b9a7d89be7f7a3f82f34628063596ce73129905c0020b9bc0ad;
+}
+
+rijndael256-eax {
+  60d7bcda163547d348b7551195e77022
+    ""
+    ""
+    ""
+    ""
+    56ae717b581681545bef99f97673b07d76c5f29cb1fbb3db8b99d59c99ab042b;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    ""
+    ""
+    ""
+    1284871421d525f5fea4eab5cd3236ad719701f0ab7e0f5de835de37e89c8828;
+  8f86edd1dc9268eeee533285a6ed810c
+    ""
+    9b
+    ""
+    ""
+    de3475c1039364a38f98e4ec3c432edbe31bed2b4ae2c5bad8d3ba1ec6338ad7;
+  689daaa9060d2d4b6003062365b0a543
+    ""
+    ""
+    64
+    8e
+    9f58b74b0c8c4612ddd9fc1a0a2ade2f129882dee66e9c7943d55fe32cf0c7cc;
+  c76c160f11896c4794846ecfa14a7130
+    c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f2954
+    9e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a8
+    94476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2
+    a59e5bba670ccd7caaa3eeeb6f7e45093846a32546fa3523791b2f132404d9a86f0f35fe46232811cd5b654c9e275c6db7f79e530cde3ace91d7a637ac4cbde01e09560059afc2da7aba6c16c5dd412608263b33187e27bac08512b611bf3819
+    21088f614b6dc3f1ca5a6cc1dda35b59373dc77f9a4b91954ec75ab8ee1f3d4a;
+  b03fb648e27fff63102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee7280
+    7a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b
+    0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f
+    7e11239c076c83d990ba728f083f5e6937e80b81d31b1e8bfc4dd1341e4023a3b403fbdfc112b81795038ef923c300ed1c7a49399f873632ab1d48991e4484e3ed7ecbae505e69dea28e8bcb34d19a4c825d17ae6b3000d69c7729c66a4d75232e392573c4
+    37ccc36ae5a0cfb968bc686d6c61844a13d059ade69efb70bffcc7f4527e7db7;
+  1dad89d4b9b12012e4713df46795630e7952d22b
+    ""
+    ""
+    ""
+    ""
+    2a04e16b231801a616818eb325a3b6b4455ad7f0feb221fc9cf7ee7ae1f77975;
+  b02d7100b8b649377d20a8f083455b663e4ee131
+    5f
+    ""
+    ""
+    ""
+    c60fd57a9134b835c1a6ff8feb240db21bbba1f499562eda9487ba0046bcdadd;
+  3c8f2aebfa921451dcd1af5813b70d30ce2f1fef
+    ""
+    6e
+    ""
+    ""
+    1c74926dd4c104bb6b4547117904d442e2f3a5f26fe303f2777d83043f70f6c6;
+  f315d0798391805da08da3aefc5f8584b7c5e617
+    ""
+    ""
+    66
+    4f
+    4aeae19b9dcd25ad5b8bdfc749075ee42ad0352e7d335e6ef8c1b4d120eae1d2;
+  9c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb
+    16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5
+    aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0c
+    fa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374f
+    484516291ddd8425984d5b20f7951606f6992d02d8c39b044d86ebffbda479500671ec82f8c95889aae76eaf968a38aadba8c8ad820f319a72a6c3ca67d62df2fa069092c12337a22ca4be8438d851ee7ceb4cc6479af0a0cb8b5d6ab3a3c33c
+    7fcc60c87daa5c131c20ef01161149e738b313743c0165fe272fffa6b8e04be1;
+  fc9bc597f56ccbb2f294b38766fc69f6a9f2c094
+    5ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d
+    65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9
+    e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add95
+    80366f86356bf3c47346f4ed75e7d21bdc49ccc63b9e606e3b322c53cc173537b7c43254b80bd6c044e2b778eddb8ec32d126c5cdf51c6e3bd13c5f48f8cf1e7596ee01b4ed1d5484ec4373aab252d08f61b8cb40c7ce46b561918f78ae0cdebe8159e900a
+    8210e8551e214b45eb7e34f359022505753cf6a60dae9a31c4baf9d44abd7f87;
+  89d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5af
+    ""
+    ""
+    ""
+    ""
+    fd2fb424608049e61223ddd23da663c101854f3787a5bf134ebc623070c80e88;
+  abf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589b
+    fe
+    ""
+    ""
+    ""
+    bd15c0ac8e80c6804cb853a059119ba0beec66a6935ffb590c4c6aa53abf9b89;
+  079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6
+    ""
+    dd
+    ""
+    ""
+    8828d3a99b3ab60db2a397ddd9f0a0191aebe0e6a0d6f4020f3a281fc67765ec;
+  a7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44
+    ""
+    ""
+    bb
+    a1
+    68445bb171a21e07feef9aad62a8069f645b621974ac7260589c4b5a5a309c3c;
+  c8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf8
+    60b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e
+    86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f2
+    4e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9
+    8f3a1855096bbe241f41b1084e58348e129ae4256d8b73414c3bf9eef729acc2f8a5a6f74ed553bc315b0817f0ab372ac20a58c13dd4e7610f8a090eec8f83189aa3341b36b90254c6893f9b58d3e611b7de06d764f8db43c34ba917809ba2be
+    c8832fe8c57e993797f82b5a17e027e875e72ea488f8baa729ed8d21db907479;
+  f81d14517ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c88
+    08847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1
+    397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146ac
+    c3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d
+    74730c45d4e79313a2d4dc9fcaf3b1f00d7a79a35e3cb48139df5572d7d26384bc4547b53cfe81ae1e756a1fce648140acb0a11a9bff1b4a36e3937cfd01530279be056525885a7e33780f3df2404d44d866e2b968bb703ba65050343cce7ac7f37f17d3ca
+    92dffe3138ec6f4100ff81315d0e0ed88a060a3542e6501979f34cd57c8d39fc;
+  98edabe08485290a4d87d13b
+    ""
+    ""
+    ""
+    ""
+    5d70d40b83d7893de0ee19cc043d24f37030e50f04e4670543a7d4bf20fce7fe;
+  07398a1458c2c6b61dbdbc1c
+    cc
+    ""
+    ""
+    ""
+    46eaab4431b6623fda169bb2106f6facf930e13c6484bf477e1d2f81e4134205;
+  ada8c1a0a9aabb6c4e3c3554
+    ""
+    f8
+    ""
+    ""
+    a9f67f2c4c00e287548b6518e7d04080973a60280a52dd2c239c63b2ddf3dc13;
+  fb1ef61614c270295dfc0ca6
+    ""
+    ""
+    55
+    3c
+    9ddcbed5f12c814a6b3cd8c58e52bdc8de3a56e19a764633c48d9d1087b0aae5;
+  1ca4bdb75359f91cb9d92105
+    6b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f
+    4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837
+    bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e
+    876d50aae158510c3d5ef05417d3a1532ec91e08ca4bb7e4abe971f7c37a8664b39483eb2754b99085dd6f33131571ac6132cb202eb43bf75cc87b0b8848ace90af17f93c4793b4cd454b84ccf6bc2c79cd9c5c4ffa670dab2db3933e0b5a79b
+    d6e3a30fea2cb62326007770a28f211f7bd318ca7b4b1e2cdbbffe8b4e5f4aaf;
+  2a1681160ccf055f0fd3001d
+    a597a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa96ffc3
+    d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb19
+    01ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0
+    df7563a9736256abeeb7e528afd5868258e5eaa52b09d86eae63321459d7b39a681aad1b3ff8fb742a54f1a07d511162e9b282e50e24ffb8a3ad99b6a284f644cf82fc460fde1bbd338510f55e14ace30d831b9b7339d8129ce086330fad250c6091037555
+    22faf1c600ec3c2e7eaab84d8fc7b1a5fb63ef32d7161877da051ebfaed826bb;
+}
+
+rijndael256-gcm {
+  60d7bcda163547d348b7551195e77022
+    ""
+    ""
+    ""
+    ""
+    155fe406a3e36d08993ed00fcf78b03f9885b8626ffc1c4005c8f54a41d46bbb;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    ""
+    ""
+    ""
+    5315b508de9b123b9d77bb1999fe58c3ec72ae1e8beade22bdfb1375e9e18d1f;
+  8f86edd1dc9268eeee533285a6ed810c
+    ""
+    9b
+    ""
+    ""
+    6e1adb0aee567f8e7b58dc7acacf8e2a46fe0d4607e84afdb57725a4c4c62f8e;
+  689daaa9060d2d4b6003062365b0a543
+    ""
+    ""
+    64
+    6a
+    414c6496cbca39176224573e7c509b4f8df43e5cf5a02344cf75a5ba418322b4;
+  c76c160f11896c4794846ecfa14a7130
+    c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f2954
+    9e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a8
+    94476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2
+    8a0b21b3faf752a732569ab7ca7edc0abf9ba5e9700cb599ab530b374c93ff7825252d41a0eaf26f6eb98fb43ca7e38ecf59c1b6a008c290550aa1fbac54233f5dc3befcfea5687b7516511137cbbbda3bb51357375fae4eb18f948350d4e9b4
+    c70aefe02e2accd4c5e7567b52e38d2f1cd68d2621cdfe4303bee6ad1285ac57;
+  b03fb648e27fff63102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de1600157846b710
+    ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f7
+    0800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc815178487
+    4b27aebc1cab373e6f5f94978fbb9dd4ab846dd4c8e6659351837bc075a78d472dac621172e1c5f4c0c184381cac80f27999fcddfc597dc5f1e96106f4c974d12d3755de2be779cb06402712144fd67538d2278d7c79eaf7e965d62aebae459883e94598ebc722fb5f
+    91201ac6618b71df23cf770cb2be511fa68ab0bb4666fc5a0f166c46fcd2af60;
+  3f0eb5b647da6794c18b5337685a96ed
+    65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd21
+    1499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e61766
+    9c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0
+    a0359a3a7cd37068cef9616e836e0dc51340c61800a8ca0c9a4e9aec807ed440cfa72d61d992bb4fd1ca3437804b9d3faae47b32aa37b2a2ea954c2bc6a4dfbe55ac20254bc6e65e257316355e37255c3358c287f9a85a809b1a339f928c7bc17d950fd4c7
+    e1169f11b3af523780b7d6060ff7541119b99e149254be2ab460870fb20e0d8e;
+  c6f21195a3b9f4ae985511265febd11c164720ee
+    ""
+    ""
+    ""
+    ""
+    88853f7a89a9d6ca3dbc23486aeabf94200f7b0222fc7c571c1124d33ad4bf09;
+  f9eb1c8dd0b00951f284649016ed00456331854b
+    c7
+    ""
+    ""
+    ""
+    705d0df1dae2209b02474644445391b9e6196b397ef49928be8dce7b1ba104c6;
+  8bf43966eb0cfa9138ddc39908445608fe95e81c
+    ""
+    25
+    ""
+    ""
+    b1bfbd95d722b50e894535c7eb30e1dadb37f0c0774adb40dbad72e986b9e36e;
+  33e31c9c1a9851bc2810d858cbbc8424d126b807
+    ""
+    ""
+    e6
+    20
+    2cbef7fa0a697ec89874abb08dd7230ff6fb9e0eca0c5a694cab36328c8c95b4;
+  daa089c3f9099c5ffb824173d7634c04226f30cb
+    b7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3f
+    b90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b68
+    7fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65
+    aab8f6ea96180e63aa3855416f27313b857947523e7341af0f8f5bd496ee8911a3dcb2db4514168dffb034762a8085a0785e79c8a67ca675f114e9846959d67fa3a333fe4bd09f7a118d2b2571a4a20d8c97c6e9428715a0fcf86a684d22faf5
+    d3bf734339230e22db1a351306eb33335985be58380bfd61d1fdf52067ab901a;
+  bad397abfaf529ee41cf9a05c7efedef3401539c
+    51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25
+    014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891
+    bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d
+    18fbf012c8917f257b87572611b9618701201d22196532e1fd0375bb15585569238d33c780cfd180db25b82bba0886360b0d8068858473f594f4ec46c069a8b5367266a50cf5b11a2285d4f11eae276d1aa24d0a2ae91d6e9d58b3d342ad1cd576faf1617d0b9ef982
+    c55c8221055fdf8cc4ff383c13866d83810e0c355df37b4785e6bd3a260e961d;
+  405e51881e99027b8ab9aea3ccf860b000974076
+    3d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9f
+    c214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f2
+    4e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d14517f
+    6efc84f2bf195615f673c68a0e16fca98d6d9a156a74fb40b74ac9fa50db8c0a34d5b00793827ee2bcb942bea89ba023867de0d00f5d3066c10a035c5f626a0bd92da3b57312ff0e78fc6efdb08d7421a68ee134b28a684ab52b84f9f629009921d80ea20f
+    1fb7f4fbc9bfc6b37ab7006cd6c661f5d8151f71f2e510af1edc1cb27a97c19e;
+  fae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c880884768921
+    ""
+    ""
+    ""
+    ""
+    5cbb3eb9742ae2cce92f5e5c9e6fa1875edb5f6ee2207e3ecc61c06370f81105;
+  1450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a
+    79
+    ""
+    ""
+    ""
+    c1b0dabf513241d592852453e603c0325644288f76937abf90c8b53cb484f508;
+  74a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44
+    ""
+    dc
+    ""
+    ""
+    9b8c23ac703837dc613935ba7bbb64343e29ed170ebf189cc79b301a6aba61a8;
+  8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d230
+    ""
+    ""
+    1b
+    ea
+    d744d421289bb50dad6cf39990222ffd62c6cb8d2a1511ff27367827224e6eb0;
+  43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de691
+    46acc3ab6cf8556b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d953
+    9726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1ccc
+    ada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cb
+    c4a2f019ff18e90fa3cea69a2f34f2d1f2d498af1173c860fa6b6f20e91781ecdaca5cd4f674027476d9cfb5b921c2d5686d1bc581b70b63feb8042f4d30deeeaf44528b6cddcbaf9a5d6ee4144fe4be1b526f3ddc573aeefe159ad33b9677e0
+    52b3da4ccdecf74bcf3d144ab23854db12a64df3ed547b78da9214f373d9d5c8;
+  cf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3eb
+    d66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867
+    642d25d54756fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd
+    881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf858f938f6d
+    cddb79cdcae1c1ecf2734f18295a6e756c73fe54e8939cc5f0f47a3f543800451b17bba62b7af7796674b9d882b05b9b1d0c39a0dfaef98c54f64996105972a740c5a7bc6bfabc63e7d6a8b0924129b9552d6b0ad95028006889241b670a675e4545f21b6256bcd7f2
+    36fb5ecbc6a1f55d402f7bdb27f362b41cf037ba5b0c8b5f9a8c5b56da81e4fb;
+  aafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae64825ecd7
+    5a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf
+    433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b6272
+    35a2cb84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d907e
+    58452492c095671447a7c66a0e3e53cb2c2f6d5d9258e3a44f7e04cbe229248769719166680ff0dbf7d06ea1162b23c71aab1b4732c913bd542d952be48e1ff46df1d55fbad872957481cb71c5728e201cbec2fdc4a58bda26099d3bc64f1c6418c68289f4
+    d9d12a477bc9a18f1b3a4a9ee2b289ff2ea6fa36758427bf9d08f9a4a92b7008;
+  ab7707ca48ff5ba1ae93d162
+    ""
+    ""
+    ""
+    ""
+    3858f6b0bba7f351a9ede4c2b5fbd5c827e7e992c079ca19cc6f26b830a9c751;
+  25d469de5747bc1addf57487
+    29
+    ""
+    ""
+    ""
+    9fdad124895e10fd8b53e2064b9f2b9d2b3cda627483e9603549c80253e44688;
+  720a320fe14fd29cfc59314f
+    ""
+    e2
+    ""
+    ""
+    c34c2d5413bddb6cb1ba41791d7911bcb2edd49b6d71773f1454961f1c62033e;
+  079c0a2535ded56112d6e3d3
+    ""
+    ""
+    3d
+    6c
+    b700b74ae722b913ab72d6b1207776e402d74fa4845d602768cdc6deb15f843c;
+  cf7c71cd7d130323794e3da8
+    4a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c
+    374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd651477cd726d6f3ebcd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a8733
+    b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad09a5b8fa687ec3bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b612ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c839839c
+    1e698dd38df7f079f6b406910c4c878e2605fe149c9a4f7d575877ade356ef2507eb11ad763a153ef93464f72fb80ccf6670651a22532662e1e33beee419e8a82c8e5f1e723ed1c0db76e90b94a97985e01ddf0b10719a689286b0cdf217760b
+    7aa4400ac56abdd5ed32f35f5487361a090461e342f11168b122369d31860f96;
+  1b06319f687dbc68d9f07fd4
+    1ccb4f8cde8de201ec2680332bbded4883deea0b58b54bdd13c17ef2
+    92b0ded3caeb5e57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0
+    fce2e1b9511bd332c86e67f123377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945d83f923e66b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a
+    10d009d35f7cf513d0f5045d1520d92a4971e792b83901e518ed440e68ed1f4eaa251584ce7703195b3f2d0b19ff558713922efe13ac3e8f8a5d7f608375326aa7a7499274df4e3c963007805ebd4b66c8c52059844edf60327144ab7febb0acc2dbcc82795aef7dfa
+    02dfe024b324aa1ad7a4a9f1d1cee9c0ba3711e97510fa26ba8f87f7e195bc4c;
+  18fb8e173416867fcd0ee78d
+    dd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592c172
+    a5cbc19456c95c1bea6079f3867e52d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f23564672e370ffc37d400a31e8aac1d426ce10df73c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286b627e7d0
+    1b38a84a6de738721ed80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d93d1f8fcc53574427767396322b3bf7d02cec05093696cec07591ada462271b1d1519eedde0df37a330fe8c22ebd77705917b7e32ae88f45a34a8ba3037235e19
+    4c8ecebea3c8b010464c18f765a3e100014f564146cfb6382d1e60f5727f37bcfd18f0227c1cc3817fdac6aa202fb93606338616cd140f999d57c36cbfcfd3eb38fb4c4cf5e34a9f0a16b703d268c428e4b3a2b26b4d3a19b08b5468632020ae7cf98a5b6a
+    305e9c670143f7d88cefabee533e27ad48988b607be91f0aa2f17649d629b688;
+}
+
+rijndael256-ocb1 {
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed81
+    ""
+    ""
+    ""
+    ed3e1a85a9f92797e1fecc6ea6840a3e0474ce6a9698a720d3df978f3528e06b;
+  0c9b689daaa9060d2d4b6003062365b0
+    a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff
+    77
+    ""
+    ""
+    dfb76cec6a750934ea46b81a7e789faca6d7dfb9da0476a03762f15639df77d3;
+  bf79192a5b50ade5d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd883
+    ""
+    74
+    c4
+    d5bf8b3be61be60645f84da4eeaf832f082a8c0d6ffc3cc3dcbe0b59bee9de13;
+  d8cde8e160ad10997a21635c6d62c926
+    9029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e5
+    ""
+    05da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad
+    a0403a115ebc9ec954f8e240c84a2c9c41241258c510be90585ac99233ae5283d3761b07c48c4c6ed2d445d16d5db78c50e54f9866ba1d5259a887eed0f2efd3c93d77945b1c03f8cb8e30ac431175dbb47f03d3643708aae7f0a329eb433b58
+    a26972939b8f37a37fbb8444db5fe6689b857b639d7b54246144435926e265a7;
+  54efc9a38378c5b93bf4f2aad2605fae
+    e2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f
+    28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689a
+    ef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e
+    dcdb20cd5e1952a7585ea1a5982f5f52fa76a949f615460c564c1f19106a7d06c5b1b194d64d000a368d353e255edb34e405639298630f6dd09210b7218ddbd701c8d29996da07df9ea188c3a58f8f924cae99a9a04822d148b39e396eae384d
+    4e7b366cc5683e7f8687281003d4c70f2167371aa3cedb3aea7c7b8a3a4bb8c5;
+  23e6eabdff3bcd211499268878dbf30f
+    1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f0
+    ""
+    83455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a6
+    158feb4340d051637c994afa715876f75eb2f49e832bf4a3d8e7f2d7268f4050406b13952ec6aa85123767375335c65e2651fb803c3399c5f51278c0381b942c575470ef2f2d7a3a003fc174d62c38d4eabcb7108adf2e2eaaf6c74e13b759f37fead1fdcc
+    aaee630716b5f9a791a7941b640408defde3f1747b50bdecde2bf82723fbe523;
+  84b5aefa69a4cd52147ed12ca986981a
+    874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472
+    a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9
+    099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b
+    374a36cca45ec0f3ea9cc9bc1fb67b6c07a8ab781d118ce9d56988904518f853d2f7551f61b0d87e5afc19c5e732dc0c7d7aea114bb3d7af88cbcd21cb7d06a22eea30921d1277e4e4577152497ff59ff72e55156262bdde9729721c2dc467afb977e5ee63
+    ccbfaf10e2aeade3c72d7f465c271105ca36369bb2644d6da6706702fc8601bf;
+  8f0911e32d65cc1770a18cbfe6effd1ff6778554
+    acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c8
+    ""
+    ""
+    ""
+    acf282a61dd79a7e99740e531b665b12c199e0f66bc3f11f4a08d8fcee8fb713;
+  4cef64f6c9b53bf8f957f4b03cf43e89957f9a3e
+    8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b085
+    1e
+    ""
+    ""
+    86c6f639096f603555766a0a95549f99fd21ee543f9fad5b44d644c96114e172;
+  5ca605ac8451399587011677508a15dde524af3e
+    2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef340153
+    ""
+    9c
+    8f
+    51df0841f87c0475e6a8995ff30422fcebc313107123f17dba67767e0dcff519;
+  51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213
+    e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec59
+    ""
+    0294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb
+    0a74784147a1986b028e29a9b9ab25645be3d7cb0774e9e5acfbaba28742a47196bb5297b70ddfbf10ce5f1517abddcb29d0fd5b715601a795af85d5503033a19bd63c2533fd50f3bab3c18fbbd7894242f15adad0f1583a5a63ab9745dc712a
+    9f1f55ba4cb8865c9b9f839183519a3b3c0bb4ecc294e1ea248be64aa7f48f08;
+  3542a9cf44bbc8c6254d980398bd94e66eb4563d
+    405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1
+    288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f
+    834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac27311
+    882bc55429939372f9123390b69f5ce58d26d439fef94063f8b2e96ee4dd8fabd4e9d886e1a1362ea2f95e6e9691c0ddced94c5ecc54893643ed0e75660d43a19a2dff771b1154c860b40d50d68f514c94ee102a17dd347f81954c6ba2266cfd
+    dff24d1115cd7f5f41e72a4709896297a9cc05dade73cb71ae7b26254faf70da;
+  7b45bcfff5d5f8b6fde2893232a9f81d14517ffa
+    e475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095
+    ""
+    ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e56
+    d96d78f641edc2bf6b208202b51ec76d956f5df89026a9f64d9266a2353dbb708b28e63a6999c6adcc265ff3d348d648196d3583e5af294a9bfb31e310f151d70ba5c9735224d768ec4f9400aafcad9aaecf25fd4cd392e35e7c00fe2fd8787deb07f44d00
+    94837daba7fa8fd70cb03d138e2f493e3db5c9388cadc8e5a6612075fe49b300;
+  0475cff206877de69146acc3ab6cf8556b7aa776
+    945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39
+    b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aa
+    bb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf96523d4723f91801325e
+    af41f07118ec731dca9ce6df290baa0e5000c68a380a9572679c32437509525919c9b04362bece8721d10aaf0fa8dd9a5fa9f3770c5d5ec1a0deae996255b61fb81f894a521f939cca36fbd9f730ab0d0c17d0689f8c1ee78d4707a36c219a0a60c3fa2def
+    db0e21f651cb6892563f22ec7d4e04c8ab46c22221819f3060f64c5736ee06a6;
+  b8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de2
+    5b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837bb
+    ""
+    ""
+    ""
+    9f736b72141985c5a64c5888c112a3c872497e54cb822ec3790fc73055d5ee58;
+  4926214211a1c696ba172010abb433922a22d9fd881519165eb9d851
+    97a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b54fd9d70c70e117bf
+    1c
+    ""
+    ""
+    e7b0f52d7adf83fe817103f61ac846a02e957786c5e605057e41fe4dfa552948;
+  ae71b3a56f0e7d839ea59cc783443d64f2ed6a29b96856beca34fd65
+    44bcf86b799e2a1681160ccf055f0fd3001da597a1406d465b7b1419ea51cf85
+    ""
+    8f
+    2c
+    c93c329ab8f440bb37247f60a5370b34d34ad7decec8e6b2d160acd4c1d12410;
+  938f6daafbd656445a09898eaa96ffc3d1d2e31e4e34c94b8bfae648
+    25ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e8
+    ""
+    8fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ecfc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c738f4cb0f58a1e34c8b15ad930c1b627235a2cb
+    a213a44a04d450838aa1eff21b53902349c2af2ef7e104af43fcc781b42c9ba22cf484ff71dec347a3f15c73eb2e644fd119297807f96eb604e32bfc76a2dfc2ad53c2ea3842a06e625954689df48ee180d465a55d5df9f2caf89ff7583e6a6e
+    d09e13109159cbee4f1a32379ea1daf61be14ef11778514d79a403df22b3873b;
+  84241986c251f5b70be2367f047265264e0da72efe8995e6c932a17e
+    ab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd4008
+    8d5be74088e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d907eab7707ca48ff5ba1ae93d16225d469de5747bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d1303
+    23794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374fc43581d2f72a89584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d07585ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd6
+    fcc7943e60d8714fb6070f0bf3db4215b5bad60d25f36aec66ad4ab1c8512b26e5075077d4685495da25e954e00972df8f01ee3e9a6a29ee9d27f45bef2a2d975fa0e2736b59f7273df0489bc440883bdfdf55cceb03bbaac41c4b92bfe099c7
+    72230dfc699fa95374349b8ab1e55f95234d8f8ffb80eb193157746d5e28f670;
+  51477cd726d6f3ebcd6fadeab50906642a7de6496247060e7be3632e
+    d9bd94bb42f45a8733b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad
+    ""
+    09a5b8fa687ec3bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b612ea37fc5cc09f7f62f66b423fcd2dec5de24d264f2c839839c1b06319f687dbc68d9f07fd41ccb4f8cde8de201ec2680332bbded48
+    1c4d9a95f9cf85283b59197b0449fa65429a7de12cfb25453f01b0f7afcc5534fd6faa80ecbfc8607fe7980370d3042421385d7c684ccf71d4170db54359fcb4cff4d2d6126b587fd6b2b50279ca190f605c740546b2a0a75055c0cb2cae2506a5fd23be2c
+    fccd1e6489cf18fed4f745338cb06d0a61a6c692d72bbab24b3fa0ee9e9e2a88;
+  83deea0b58b54bdd13c17ef292b0ded3caeb5e57fd21df10bc618626
+    5ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123
+    377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b072945d83f923e66b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f
+    3a18fb8e173416867fcd0ee78ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592c172a5cbc19456c95c1bea6079f3867e52d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f23564672e370ffc37d400a31e8a
+    277fd76c5b58942c48687f4153c8d8aa6521902cff09bab07145801225bb2823fe4e112fcd11726bc62da7864baa800905c9392017a574d966aca87da54d481e320934c4d5b8858bb53c9f91170e96edf3e3b6a583677e2eb0f6e876162ebc2d9f9d5f59d9
+    af850a26c1eaa2af0c507d84542fd2a5dfda7ad3f6bbd94d7202716f0bd83b66;
+  ac1d426ce10df73c5ee478b3
+    b63d91024780e974a8a2a0e7a36f84ab1286b627e7d01b38a84a6de738721ed8
+    ""
+    ""
+    ""
+    1a65a7de04f027cc7ee41a321985a03044b009409ea0a04a6ef4f268a40d647c;
+  0fd0d7f69fa658abb5a440d3
+    04128719b541a9451cead18e4c61d93d1f8fcc53574427767396322b3bf7d02c
+    ec
+    ""
+    ""
+    2257228003251d6931be43f6f65654859ae865666736fc80b7ce6feb69cf8c4d;
+  05093696cec07591ada46227
+    1b1d1519eedde0df37a330fe8c22ebd77705917b7e32ae88f45a34a8ba303723
+    ""
+    5e
+    44
+    d4ef8d10bc4dfc028117bf6b79fadd4498eee972464c390c38cdd44837eb3a8c;
+  19a394be4d26ce47317d8087
+    684456b4cfc5555e925e3e7b2ebc829b2d0505ea617b0ca9531bcdb96040d390
+    ""
+    40e632d562643ccb64286303040fcaf679e914eaddc05af8843ce6a427b99a5dc266de31c09165237eeefe4b58cc034b9f099f04678c2a9da898b39324cd3087a651014f6796f9c4881d89e127e62221e47e57badd678d490c2f320ff8fb1c42
+    2702a4cc524f8c7eaad3198222eb31272dcbd5885798ecd2767a8e9292550feef8f1a6ce4c615967cc154def805d429a2964b5202955972c106deee2444df7dc0a3ba8940bff435cde364f1a43e4e5081d6bc4296ffcc3f907152b1e01e892ea
+    37ede9a353c66446268a96e3101e6716b5a0875413bf2cc714720277885cf14d;
+  761bd439f3e96dc0ed1d5b21
+    69912af1a4e2c533c52ba3e8c71c23a089e231480aa63c484fb34bd522397f10
+    2cb8ecf4f64e329884fe73be257a753b38200bc23f94a079bde2dd98d813655dafa15b85419d15c41a5153cce5d0e8c8702db2ba11927589678d4f7b8fcfad4818c411f15f452300903874f9a532ee46496ae753a2340af7b91f9632fc5ae71a
+    e18b40de751ab6b6761ca16434a9935e466e11c1cb072f32a59c313dba3db646ae909a096697d9a7b0556463ff1126ebc43263391424d02739d0787e804d8f1dccf6c897a8a48431324324041b5302ccd501b538bd03d5cb5c90d1fd3f7d2be1
+    f03d990fa20cea58d5d15c20a6a8479f8a2650c245da7d5e8505e2e32c924d6332b7e8cb40139bb17a2b6b95a200c1f4cbf967ec5ca8bbd04db6f70a767067d46fcbc066aeac04f2a3f9e647b290d31f3de21a9dd0e757274c1623319d1f98bb
+    129dc99b2b2d0335f5453ba882fa4469e4617169fa9f3394fbfeb4a9fb68925a;
+  87a787032c79ed900764ee4c
+    e1d3fc042c084f7d8c0c48ad7d6f1eabd0fd1ec24a88f26734d5c8d92dbd873a
+    ""
+    8fe113090d401bea4d28ff49f10ff593adc258e091abd31b62dd1735158f98765970acc6602da063aae01a2a199d3a4f37a5f062d216d2053a83b5d3a0488ab0d2df631b2892cdfcf9fdd0f37de9ed67179aeae82fe00009428b297b553230a6d917fa0c1a
+    7e3a6085662512c823d6d9929dbcca2e1833f6589a38fba924c2e16d6a1d050b7442fbbc2dfd750c76235c96aef4d0d9388c457c5c368c58325aa09623297e6c4a5f19b668ec3ace50bad6c64824ccbb0ba3c72fdc5041ec93d3f231321f687906e3ebd93b
+    54e6538ecb2b4903cb6f375cb5956c92de38b1584b08cff45916a3c4b1f5ac84;
+  233c9ebc8a4cba45b20543c5
+    40fc1b9dbce078b87a1534acf03897b95a3f372e9f6c5a5f2ae44a7dbce9ba43
+    a39089de20de70d0544b5151db0a16e9769e8f2fc12c7f839fab269a0056284a697ffd4113a1cf43b5d5bdce2d86dead83f5a356e9106bedf908db61f1119f9700260ea9379cc7232184d217158fee8ca42e75614739e9007f234f
+    bcd86b0ad8f641a0449b6d9b0f99d1cb4a57a4d6f987feb0ade90aa1d81c4f497b3734be301da3e25fe692629db57311f422f3a1573f9e0553a23e96265e4326fa532d7136863e5b4bc6c99ade3d4eb23cacdf6e42ad8ca13187eba1532920ba31582b3793
+    c65596e9c53e56de712143c2be771a3707bce914410b2e32fe484f74a6210d6ccc48122d4df80f2fdf5b3da056b8742ef07b5ed7c038d18d61da0f5e6584c6af306d1e11ed69ced0594202b10cde788cfe963d38846daa71158909e5fc051dcd0b11b2a8c3
+    e450cf5a72fbfbc72c1249de355a6c3fd6efbb4bf28f68c48b286266a7a2ec6e;
+}
+
+rijndael256-pmac1 {
+  60d7bcda163547d348b7551195e77022
+    ""
+    932f0d9371e20b910a772eabeed12feef4f4859c0c0d15200b2060df6a3cb6a2;
+  907dd1dff7dac5c9941d26d0c6eb14ad
+    56
+    9a97ebc929e438b9781ce3263e5f78f07fc74cf685c00cc7e16977985459a03d;
+  8f86edd1dc9268eeee533285a6ed810c
+    9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd883
+    27ce94c2d0af1899c43ec264b5ae7ead31b2dd65f45f3fe0e95cc0ac6576f672;
+  74d8cde8e160ad10997a21635c6d62c9
+    269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52
+    571b59ffd88f5aac558bf81218c3cb2fdd9e800b3326401c649e53bd5a406f57;
+  ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6
+    ""
+    2efae48af6eabef0778e76390430974fbaaf244c3fc6bbdb1e58b13bcb580fb7;
+  c95a97a48030370c33d090c54215abd6b3ad54ef
+    c9
+    4aee747efed92d046967d15c7fa52ad582133e03a0a177ac602ab5666e5c23cb;
+  a38378c5b93bf4f2aad2605faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2
+    e5afbb13c8243b7c984eeaa0307277e7092658217292fbf05e8d0a56e3fc1b21;
+  712a199e533fa9156308cdec3f768281e040a9b9
+    a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c4
+    913f5198775e26d1e0f6c2a2d05e26b280f7ddcf117f19afaba1ee0da1426e70;
+  6f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad
+    ""
+    1f93abf128d33b355c0a88df509ac50535f22ab4fb12799f703517544aa9acb9;
+  89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20
+    a8
+    3f86edb2b064d7d351daf60764c151d2f8759968ece6d3f000b792f6c3c92faf;
+  f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f
+    1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abe
+    27080744f866bf654524ac485f602841ee45bda2e22542f55ebee2e275952bff;
+  f8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784
+    e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c
+    17313b005c8ed5153fe443e60220e8f21373fccd865532655f15d74393767da0;
+  5ffb824173d7634c04226f30
+    ""
+    f4a17475609b3057cf1af06d015538a527b56fb849c986850c224ace1775cbab;
+  cbb7f0e4a973a8cd19010731
+    47
+    74a4cd7ca684aa5015445562c68f2c4dbdf63d4ac5fb0f392eaf16b533fb0304;
+  17a77456f3ff669c732b58db
+    8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a4
+    83b54ce5e25f2c786bf25fe30336fd71900040f048dba6e99d175ac195510fac;
+  58cb948bdd409b687fa3a682
+    7b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d
+    631ff4d45f8f6536dbc36c29a857d440c7769e87829b468e051e0de73f82940a;
+}
+
+rijndael256-ocb3 {
+  60d7bcda163547d348b7551195e77022
+    907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6
+    ""
+    ""
+    ""
+    94cd6ce38b3c77d05a0a0d25c295a65a6b7d7dfe954b0cefac92134d2864832b;
+  ed810c9b689daaa9060d2d4b60030623
+    65b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c95198
+    48
+    ""
+    ""
+    405c363c87384173bb83480d788161af11844656e9cef376f25b82bb5e1c537f;
+  a877ff77bf79192a5b50ade5d9cd739a
+    3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d
+    ""
+    8f
+    0f
+    66d804966f42b17b54de7c5c83254b129c4ceb4a428c76c4d8d06cc3efa3108d;
+  a21f2dd88374d8cde8e160ad10997a21
+    635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3
+    ""
+    b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a4803037
+    874bd486ad241e305a5a00887137d77528095262228eb73fd52f1c6e6313600da01bf461d676730308c2c61feb98f1cda079b3b4372c6c3871c434c75972bb12fabfd29bb6253fc54ba1b93a30fd2bbb0d8552886c324a268afc3049aec44900
+    5913eb9194f12a3cf55bc082c9dc16ea94539318585e88fb31cb62f6732e7004;
+  0c33d090c54215abd6b3ad54efc9a383
+    78c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26af
+    a3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cd
+    ec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b
+    0ff57de3d2cc21519dd3d0f49fda28b2b5be55e284d48d36e5cba568ae1e8b58fa124c37912109af141b0f186c2fa348b62ca46c66b6889aefe7d2feb01a0379069e051ef893b2a1b40d67aa04b99c53ceda7b3bcd2b7981638e4d8a319e8283
+    68dbfe675410e257abc994d87e0d6b3285ef039f4296e4a3ef6c3380e8b9d057;
+  09c063c46f88de9fd41e72d7b97e23e6
+    eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e
+    ""
+    7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c
+    c5cbe3643d4234720636c3db98390cf32199996b8ce59bc07885a360d5cfd002cdf9be271301983a242a71f966668b54deb6cc8e602c11b4db33b0ef65437bfdf4a92d0f923f9997c3c74c3d850b8a485615e0b50b07f76cb252602bf211492cc980113905
+    5470a7b06cc51ec77c63446ca423d3153633f1957329423be3a685b42981dea2;
+  31e6bc58c0b7cadcb658b970e47479a6
+    84b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98
+    ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc
+    2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae
+    870e6e1f56383e064accc0744f1b450d79455adbc72e49461ba13564ccf944450db7425db27c41f82bb0a36397116c2cd1a1034920fa12bdc9d6fc62cedef298195a8e05dd34cdef1726048ee2d8c9ab7d5f46f8c9446baf704c7755f3ee8d91a6fe91b14b
+    67d3c0473bc44d9ab3f05eb918cb7161773a63428d9d399854041d31168df643;
+  9ce021a5f1fa4ffa91544485f1a1258b2b9b8f09
+    11e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967
+    ""
+    ""
+    ""
+    220a303425f9a53ce13518047d3dd5d8a1d2109ac835eceb441c5a586185f99a;
+  c0a458cb948bdd409b687fa3a6827b480aa3a4c8
+    4cef64f6c9b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8
+    de
+    ""
+    ""
+    7c5abcd9e9323820d615abf862549cc31c1b4e1a1e4da3e5433ba6e39e5bf538;
+  b9bd205b70e04c091d205cdad9e9a79b1abf91b0
+    851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2
+    ""
+    ec
+    a0
+    3fce0fc48d3f0d7643ebeed0d4717eaaec3f4e2dfdff01a8785fb143e532f5a5;
+  ccb44d65bad397abfaf529ee41cf9a05c7efedef
+    3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e
+    ""
+    8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde957
+    61bc90511fe93f33ef7e6ab4413c9a0316b1c5ed6f08f6b01242a31e226cf226df4af92db146356f1085cca26df2fc170b84f4b8106ecf2d83fad1572c3be1c30bdbf150035a6133b3ca54639084608bcd0aad6999675b63f2550129a01dee57
+    3310b19ecff1df1ec1e41c327a823ad057d4f4f494a867a029f27be5f9c540c2;
+  59ac46fee6dda7abc8ad68daac90cfe22d2f1f29
+    68cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d
+    405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf
+    1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383
+    134807254d64c7724ed92cdad040f7f59a768628d3d57c45bd3eceae504854100ec839b7c3ccac4e6644fad7812fc05834435d690b67bedb6f4801c9c4ae2d8fbfb1c879e6546e6db284071ed8ffb46ea8969dd3ca48cf3872c1a7d80ceb46c8
+    b379c41bb4390d6908cfe111a9dd6dcc768b040ffe4af315f3cef5e0aa8c86c8;
+  a8cffeea7c486315799dc875fba578c8ec483789
+    8a92142b5b0677da1ac273117b45bcfff5d5f8b6fde2893232a9f81d1451
+    ""
+    7ffae475f6b94a43a67b3d380d2f9aaafe2dd721c0095c8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74d
+    7b5de357d72bd4a66e08bdf26b45f5d47e4c4042b89c239682d74e9bb1cd0f544aae03e377c97b30688249beb16e2e43d82c7761d7e61ceb853ad2209c68b405e99283fac3df1c6c2dd8222a9adcfbe909f0fcd81692e36a49b04dc2b1841f26145fcf57d6
+    dd6d1166ec2c7975dcdb49e29a3d55ae62fd37726266e884efea710157757b61;
+  c23a7bb40e7e0013e5150686d2301b43a15a84e8
+    1d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf855
+    6b7aa776945948d1b8834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa4dbf710a9e544e0c536ca1e040f9
+    ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270295dfc0ca6551ca4bdb75359f91cb9d921056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4a
+    8257b8b269a4660300f762471821ca7a83d067b72aba369efa0edf5900693daee8da585e8f41aacde010cb5efbec25bd2ad47c1112f5ae87f79180659f3eb86052d760392fd1a268c2e75ad6e6dc447f5581fbd2aaf41bf7120c169688c8043b3db9f8fc1c
+    3d62bf30f4aca83ca3198e4d91e2ac40c9c6e5be1f6e02943f0a947022425d5b;
+  e480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fac7cbcf9652
+    3d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98ce
+    ""
+    ""
+    ""
+    5f89715a1b8c7fb4fd3816b482fecf863fd5ffd013258827030d840fa2d2a1d7;
+  dbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d547
+    56fa5c47f16f64b837bb4926214211a1c696ba172010abb433922a22d9fd
+    88
+    ""
+    ""
+    065b3d824cbbad977cf67a74c2dcdf3605309d86ab3df633aa3ab27347e44e82;
+  1519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5
+    aa47b54fd9d70c70e117bf1cae71b3a56f0e7d839ea59cc783443d64f2ed
+    ""
+    6a
+    69
+    9a88da0ce1b21c5c7ca8badc6b9e8e59ed577ac39b0af14fdab20b02dc9df442;
+  29b96856beca34fd6544bcf86b799e2a1681160ccf055f0fd3001da5
+    97a1406d465b7b1419ea51cf858f938f6daafbd656445a09898eaa
+    ""
+    96ffc3d1d2e31e4e34c94b8bfae64825ecd75a66d88eedb969ffe07669845ebb7a24c69f13d099f47166edf54538e88fbf433a7ff212085179e79771f6eee7283ab178ef2b800d7b969da05780ffc1ba78c70dda7a4ca2a25e771702fb1901ec
+    e3e73214e48c0326b4e390a35aa9c0d9a8696a196543c3bf9409f2675fedcb4b5b369ec744fcb5d2ee7a5e76549f1f9e2a7c98b1989349e37e82bed729c9278ef0a925fdc7c838535dfe0351f8d7b3be579c9b17382ab0720513ea9c485097c6
+    ef9f792e7eff79fb841852ed80cb6b30429520d077bbedde0d797735230dca6d;
+  fc8a959cb8e75079bb018ccc8c54f31b450e88f8e9002926ad0284c7
+    38f4cb0f58a1e34c8b15ad930c1b627235a2cb84241986c251f5b70be2
+    367f047265264e0da72efe8995e6c932a17eab511eddb8e4ba463c663035a6ae8a7a899e4279d54d03f0e0f3e961dcfd40088d5be74088e4097efb0368c7e2f431ee6988cf2a0e9ebeb3de79c4f86c9e4fba61339d6d907eab7707ca48ff5ba1
+    ae93d16225d469de5747bc1addf5748729720a320fe14fd29cfc59314fe2079c0a2535ded56112d6e3d33dcf7c71cd7d130323794e3da84a9df69703a9caf02d2a8f57ac71e554a6850d55882f8c7ae6994fc8528bd18c374fc43581d2f72a89
+    17bd1896ca1775f27a78f55e568ac95360963aa799f1736346c94174b2749d9626a2d11af0a3717f4ddd4bb7d71c27c834cc11973300b851590c28bc90e377b9c672be42329e4fdc2b8178f54727f529d6c6c973ffef4bc3d829df42e2913d93
+    0666959b0610c0e4390049ff5339e64bf450a485947e7ced421550d5b4237143;
+  584a2404a059f7f99c7241a0c879d6d4455b382a9ce757b3e7a1d075
+    85ad9d7ea9c7c9cf54f3bc6d94238ab56d738e02abd651477cd726d6f3eb
+    ""
+    cd6fadeab50906642a7de6496247060e7be3632ed9bd94bb42f45a8733b2cd2df9d1d905cfdb29983050d6bcdb686a0c897031ad09a5b8fa687ec3bad8e18dc2ad361f1e226e78876cd35f86c639733c5cd84aed8aaebabb7e0f24edfd9710b7bca91b612e
+    d98615675232b1e3b446b8ef49645238f92b1286e06f32a6086476e1cf2636ee4591be6c515a03f84c5f5bdbf0550ad6440e5614eea29ff878fc7a1a59292ee7076722c6c12bd0561eb01666fc0eaa74acb29400ab1af944693f08c3df1202efb9aafa5204
+    4ebd32cea5c4e8e22ae8d025273d736a7aa4ea99ec35555379d29b64beb35275;
+  a37fc5cc09f7f62f66b423fcd2dec5de24d264f2c839839c1b06319f
+    687dbc68d9f07fd41ccb4f8cde8de201ec2680332bbded4883deea0b58b5
+    4bdd13c17ef292b0ded3caeb5e57fd21df10bc6186265ee6ea45907de6cb822fb2ef953aea358a03e0fce2e1b9511bd332c86e67f123377a8f0256b8dcc73ae1b3c6cd3f104e3cb24284cfed17811d64d492d39ea7496993a25b07
+    2945d83f923e66b0a6689cf0969c003a8fca80e322a4b1bf050c1220450433efb6b6d8a2d820cf27a64b9d47f636845dac557bb3e75f3a18fb8e173416867fcd0ee78ddd9236beec76d55ed58b10f91d07a037791ab96e83c4bf2fb5b205e592c172a5cbc1
+    d9971e97c6107f5e95716634e4731360542765a84d798c706f88a6dbbe83b4d0588bbea20e927524f8d21de8ab71a910ed5bae27aaea95bd20fb05563fca2674cd6037d9fce9a1ea0f47fae536d92b837aa391a5a8f6c9b4e5280b66553d7516df90b4bed4
+    ed3bb7517af2601dd23e9c5b54c63eeb050f51d15acdaebd6bc47325ffd33ff8;
+  9456c95c1bea6079f3867e52
+    d663cb3884b2a0a8ff825df752423f3179bfeb89eca385f20ddce5f1f235
+    ""
+    ""
+    ""
+    d7bd5a595d894ff087b4120947bda4fdeb956a41b2e9fe9152dd2071e11b0552;
+  64672e370ffc37d400a31e8a
+    ac1d426ce10df73c5ee478b3b63d91024780e974a8a2a0e7a36f84ab1286
+    b6
+    ""
+    ""
+    affeb59e316bcec613e4ba87e80e83c1204f83e9aaba7de2263c76c1778c3c34;
+  27e7d01b38a84a6de738721e
+    d80fd0d7f69fa658abb5a440d304128719b541a9451cead18e4c61d93d1f
+    ""
+    8f
+    5a
+    92a3d896a62298b49df5d041c3f30f3ca01a387e04bcd3e4e934789fa270f485;
+  cc53574427767396322b3bf7
+    d02cec05093696cec07591ada462271b1d1519eedde0df37a330fe
+    ""
+    8c22ebd77705917b7e32ae88f45a34a8ba3037235e19a394be4d26ce47317d8087684456b4cfc5555e925e3e7b2ebc829b2d0505ea617b0ca9531bcdb96040d39040e632d562643ccb64286303040fcaf679e914eaddc05af8843ce6a427b99a
+    984c933c9aa7fd8536cafe98d705ee19c027a3c82e1f655b87325e8694d8982e7da50abdfdda9b9275c6aaf0dd141b8f2c4fe0d4b32d1317efccf6a1768da9d15699af7c8fc90eb6386648e098795b80380933001d47f3484b771cc6435e824a
+    300a77fde5151a0a55110605f648e984e5c5e9c297759b420773e0198fd43de6;
+  5dc266de31c09165237eeefe
+    4b58cc034b9f099f04678c2a9da898b39324cd3087a651014f6796f9c4
+    881d89e127e62221e47e57badd678d490c2f320ff8fb1c42761bd439f3e96dc0ed1d5b2169912af1a4e2c533c52ba3e8c71c23a089e231480aa63c484fb34bd522397f102cb8ecf4f64e329884fe73be257a753b38200bc23f94a079bde2dd98
+    d813655dafa15b85419d15c41a5153cce5d0e8c8702db2ba11927589678d4f7b8fcfad4818c411f15f452300903874f9a532ee46496ae753a2340af7b91f9632fc5ae71ae18b40de751ab6b6761ca16434a9935e466e11c1cb072f32a59c313d
+    ed01665286324cdff1c38648e15ed6c53f9ad08c6d830bbcda44c1a43d662b55b65a02493a13da360250c8f67d83042de2a3cd4b5ef58d6de79ab9b29377377f43b179889b2d73a2a4bda38c8018504a3e3366be90700291e7f9d676bd764661
+    7ad70b7407fb23e1d1cd1aff53cbbd9b27b27f3d5323b2492cb700d6c336a73f;
+  ba3db646ae909a096697d9a7
+    b0556463ff1126ebc43263391424d02739d0787e804d8f1dccf6c897a8a4
+    ""
+    8431324324041b5302ccd501b538bd03d5cb5c90d1fd3f7d2be187a787032c79ed900764ee4ce1d3fc042c084f7d8c0c48ad7d6f1eabd0fd1ec24a88f26734d5c8d92dbd873a8fe113090d401bea4d28ff49f10ff593adc258e091abd31b62dd1735158f98
+    13c29223881fcb5ac5bcbdfed11fec190f5616ac0b9a48d7c500416887ffeceda025cd1a53cef1b43980cf4930680e43727549984acf076bddb90b889ad22a81bf371bcd9b1bcbcb8e1709cce01ae25f6bf51424b6ca9c6f54cddceff6a536df344e96d66e
+    6a5e940b5fd47e1c52ff1d6e898c535bafb686a2b12931f0d5e4a902207c5267;
+  765970acc6602da063aae01a
+    2a199d3a4f37a5f062d216d2053a83b5d3a0488ab0d2df631b2892cdfcf9
+    fdd0f37de9ed67179aeae82fe00009428b297b553230a6d917fa0c1a233c9ebc8a4cba45b20543c540fc1b9dbce078b87a1534acf03897b95a3f372e9f6c5a5f2ae44a7dbce9ba43a39089de20de70d0544b5151db0a16e9769e8f
+    2fc12c7f839fab269a0056284a697ffd4113a1cf43b5d5bdce2d86dead83f5a356e9106bedf908db61f1119f9700260ea9379cc7232184d217158fee8ca42e75614739e9007f234fbcd86b0ad8f641a0449b6d9b0f99d1cb4a57a4d6f987feb0ade90aa1d8
+    871ec85dcb564eeb30e76fa18d1c45e6e03a34fa8d3701ae975fe8ef646e5581e70a2d7de65b92d4407925500b00443315317b26a084bb65f2c3c03377dd68c814915a3215d72c409cbbd99261b6ef8d14ddc790a7a7495c7c401ab4d4041607f3f4320eec
+    8c4b5793f59a300f6e01ddf60ff510fb1ea408ad470064a3cfe0b1b4931e6535;
+}
+
+rijndael256-ocb3-mct {
+  32 e6daf3cc9ccaa1b05a68b6069e290909301ba320423b3a658c9552e67486ac87;
+  28 3cab36843515c14a36039eae083324d2ab843e04f30739848bd7bead795a6cd8;
+  24 98706671cb1048083d2e2de4692530d8259d4ca91e6f4f995f41bc2bfb575e49;
+  20 5f3ad3100cd757cba80500b2cb3159530cebb5b1309b89eff98daa458348119f;
+  16 a10c36f02737879b67ae2c4447f6d25cfaaae27916b95e40d2f36a40f9127415;
+  12 2b848a4d1f15ffa8a4937abe0bf244488eb69962143c49e942fabdc21bf05bca;
+   8 450a06d40fbcfba4feee7f6f176364093dec3f15a4d8aadc83fe1e28909b6ecd;
+   4 43de563ee4818834fa190764e0aeda79811ff574b26466ac17415f3289d13715;
+  32 42adb7c35588f8c6edb4abfc97b946a1649085165c7b8c3a;
+  28 576eaa3954cc439e98263497d95da6b5e3d8279214f574c3;
+  24 e28807d93e721c4ee87db0e382b7fd0ef97f7ea132915bb5;
+  20 af22f7a7675fad35eb8782c40bd3c732cb1ed35c97654f8a;
+  16 fe9d4746e3c184b1515a327e9e928c7a46b5a0cdb283baf9;
+  12 9171f1fd2e0453fa5b993e99a6382068b0ca625dd3f9ac39;
+   8 16823ab82ac0c840791945b5bce210ad634c57fe5c514cf5;
+   4 bed515eaca34486fb2e069335c780d8e7b9b77c602696d9f;
+  32 d79599b45b8f8293aaad48235eb95a2f;
+  28 91442e4c2c8ae92f9dc870d7c3d6e0b8;
+  24 da99ec771ce8684f4ca7ffa5df402ded;
+  20 0d20204adc374fa840fa585a2d3a22cd;
+  16 c3e2fb19d84accbbc5b715ea29ef175b;
+  12 a3643da0859091dbe415fcad234bad6e;
+   8 ab4292dc30d15a253e5a5360032cb3ab;
+   4 74b7cfd2fc50a48ac5fad7c8d84a27bc;
+  32 f53f5dd16d5986d94888a702;
+  28 69bcdf722b40237c2e8fcd71;
+  24 67e16b822be5718b363b3ff2;
+  20 3d6fa2dabad3337e26a72bfc;
+  16 389907e4b3cd3d0168d0a819;
+  12 ff40fcbbbe7a203fc704dfcd;
+   8 c67601e9b9f58b7a464e3f47;
+   4 d1b2695277c7c8f8a9e9573c;
+  32 238f3b1fc1fc218c;
+  28 0f3657da64398b7e;
+  24 07ffed4ca9d89a19;
+  20 248ef8ba5dd3f022;
+  16 b081c4be1451952f;
+  12 c6932badc879fb36;
+   8 5f41014f77919965;
+   4 3d613ca8abe9c4ce;
+}
index 15f75ee..cef5b9d 100644 (file)
@@ -11,3 +11,465 @@ safersk {
   0102030405060708 0102030405060708 60d04ad7c49b8ded;
   100f0e0d0c0b0a090807060504030201 0102030405060708 b260740f80d2445d;
 }
+
+safer-cmac {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    b9f9da8b0465e894;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    cf652451ff1ea9e1;
+  ad568f86edd1dc9268eeee533285a6ed
+    810c9b689daaa9060d2d4b6003062365b0a54364c76c160f
+    5056bba2984b1682;
+  11896c4794846ecfa14a7130c9f13712
+    0634c9519848a877ff77bf79192a5b50ade5d9
+    2c9685d013b7efff;
+  cd739a3d1f337f29
+    ""
+    b7c678291a02ea9e;
+  549e6b0d27a4ba23
+    40
+    0cb9e87774a1ef4a;
+  85406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    0a9d5c038c99f36d;
+  21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbd
+    fe61dbd63946d430;
+}
+
+safer-ccm {
+  bef260d7bcda163547d348b7551195e7
+    702290
+    ""
+    ""
+    ""
+    74955b21;
+  7dd1dff7dac5c9941d26d0c6eb14ad56
+    8f86ed
+    d1
+    ""
+    ""
+    64c48de4;
+  dc9268eeee533285a6ed810c9b689daa
+    a9060d
+    ""
+    2d
+    fe
+    a0c2fe72;
+  4b6003062365b0a54364c76c160f1189
+    6c4794846e
+    cfa14a7130c9f137120634c9519848a877ff77bf79192a5b
+    50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a
+    0f78a0e09e9cf67419d6cec4139324f10d8b36dc7b0cc47a
+    4495b1b7dac09ecb;
+  6136512061f7080cc07df0591d8fa21f
+    2dd88374d8
+    cde8e160ad10997a21635c6d62c9269029df3e
+    6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505
+    d231d706e1a93d3f14c39ffb9b4e7d849e5daa713039d171cd99e50314
+    1b755d09c0126620;
+  da1435dceaa7b1cc
+    49ae1d
+    ""
+    ""
+    ""
+    cd1b5bbc;
+  50c38201a894476b
+    3f102b
+    75
+    ""
+    ""
+    c2096bb2;
+  2eb9529533966f27
+    043eb6
+    ""
+    21
+    53
+    25a20612;
+  b7f65b000961040e
+    f2f9b2fc5f
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3
+    ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54
+    226b9bb081738ba5f6626653861db3f32832d8551f5a1b96
+    11e255d4c06111f5;
+  efc9a38378c5b93b
+    f4f2aad260
+    5faee2b03fb648e27fff63102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee
+    e06ad69863c7d36838a811277e746eb2319191c405682d38ccdff9654b
+    d3160250b4828281;
+}
+
+safer-eax {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    ""
+    ""
+    ""
+    75c1da0376977c83;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    ""
+    ""
+    ""
+    e8df12a3fceed9c1;
+  ad568f86edd1dc9268eeee533285a6ed
+    ""
+    81
+    ""
+    ""
+    67fd181cddef533e;
+  0c9b689daaa9060d2d4b6003062365b0
+    ""
+    ""
+    a5
+    30
+    b9ecf97c3093922d;
+  4364c76c160f11896c4794846ecfa14a
+    7130c9f137120634
+    c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0
+    fb58d0f5368ea912d10744647fe366bb418777601697e28c
+    7ca11efe24763f77;
+  591d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62
+    c9269029df3e6057acc87638f508046733d9ff
+    61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c3
+    8f2eaca038f7cacc19b6cbd27ee094e6a78343fcead2b02356c41697ad
+    216152ac7b8d453f;
+  8201a894476b3f10
+    ""
+    ""
+    ""
+    ""
+    b4d102bb91a06dbb;
+  2b752eb952953396
+    6f
+    ""
+    ""
+    ""
+    ebaee4aba3e18cb1;
+  27043eb621b7f65b
+    ""
+    00
+    ""
+    ""
+    637a640605c9a7ff;
+  0961040ef2f9b2fc
+    ""
+    ""
+    5f
+    f8
+    d5bfec2d60727408;
+  a450727a9b542cde
+    52ebfda19d0ccc52
+    0f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090
+    c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2
+    34969314934b38d9a462ef69cbbdb80c7cebd4e6361a5faa
+    6f46339d37873473;
+  b03fb648e27fff63
+    102758fe2b69ac
+    26afa3349829b94586306fed54154f8f28523c
+    03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563
+    27ebc64f0dc6fea2eb465c16ddcf0fb51567e3a14eeccdcf37be2ffb0a
+    a925cad73bd83f84;
+}
+
+safer-gcm {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    ""
+    ""
+    ""
+    54d777d84bb367be;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    ""
+    ""
+    ""
+    ee0bd152340f8fa7;
+  ad568f86edd1dc9268eeee533285a6ed
+    ""
+    81
+    ""
+    ""
+    ef542fad7971981b;
+  0c9b689daaa9060d2d4b6003062365b0
+    ""
+    ""
+    a5
+    68
+    9775c4709ae7e478;
+  4364c76c160f11896c4794846ecfa14a
+    7130c9f137120634
+    c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0
+    ca09cf420396beb0c928209ae8423ebaf1230ae572f41b22
+    1f53984176941a39;
+  591d8fa21f2dd88374d8cde8e160ad10
+    997a2163
+    5c6d62c9269029df3e6057
+    acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7
+    b71e6a6900bbf0745a3372bc9fb843931af8c9605701f49519b02c8c2649f8ed92
+    bbc316814a9c8ff6;
+  b1cc49ae1d50c38201a894476b3f102b
+    752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5f
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6
+    12f78c86a8fe1b71db510309fe43a4434a5ff6a2c4dc3bc01f0feea936
+    b3a2d8864a3eabb9;
+  c95a97a48030370c
+    ""
+    ""
+    ""
+    ""
+    f0d316bc4b69c200;
+  33d090c54215abd6
+    b3
+    ""
+    ""
+    ""
+    92be4864decdb6b0;
+  ad54efc9a38378c5
+    ""
+    b9
+    ""
+    ""
+    7699b3ba70391bab;
+  3bf4f2aad2605fae
+    ""
+    ""
+    e2
+    2f
+    6826c1faff7a71a4;
+  b03fb648e27fff63
+    102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de160015
+    7846b710ee72807a2219bfb474fd71d891f24bb65d156325
+    9c27bc6e00c2e0ddb8d5e399439bf477cc02f23cca50e560
+    d21750cf96e20752;
+  9f9eb53b571ea629
+    c54d57dd
+    2d42f70800df9fcbaca48b
+    77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040
+    76b11272cd887c5f6fa869e7bf52578442dd96e83b0e7cbcfdba46f67ba2ee6fc0
+    23f48c9f5534edbf;
+  a9b9a222bd689aef
+    66f5306ceb0c6b
+    08ac8b0a22260c571b4a42bb8fdb233bfa6a5c
+    fb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784
+    cac8eef1be089b75a8ddb79ca8588436e6e9bac025a6d89bac100dc284
+    d41ff215540bd48c;
+}
+
+safer-ocb1 {
+  bef260d7bcda163547d348b7551195e7
+    7022907dd1dff7da
+    ""
+    ""
+    ""
+    e2e419f8cec4dcb3;
+  c5c9941d26d0c6eb14ad568f86edd1dc
+    9268eeee533285a6
+    ed
+    ""
+    ""
+    aba50e2dfc553b0e;
+  810c9b689daaa9060d2d4b6003062365
+    b0a54364c76c160f
+    ""
+    11
+    c4
+    4586e65f8c86dd50;
+  896c4794846ecfa14a7130c9f1371206
+    34c9519848a877ff
+    ""
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4
+    07f19e04df183fe463e0f8d408918e4e90d5fa7c1fcbf997
+    8248b794a7bd1a4e;
+  ba234085406a6136512061f7080cc07d
+    f0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    4f53021f22a68a8d47c855e163a27226b624dd712fab3e2a
+    ff7aaeba71e97e88;
+  05e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f10
+    ""
+    2b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450
+    34d295b915f6715a7aac820be272519ed925b11bf0f86145df35751dae
+    9f185db0d5f8cc21;
+  727a9b542cde52ebfda19d0ccc520f21
+    5eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6
+    b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff631027
+    2efe1a659d7d670d28fbe822b399e07290be6934f6cec51e8eb0362c7d
+    f9c31f6c694772d0;
+  58fe2b69ac26afa3
+    349829b94586306f
+    ""
+    ""
+    ""
+    88301767ee937c29;
+  ed54154f8f28523c
+    03d4de1600157846
+    b7
+    ""
+    ""
+    e4b7676fbd808aa7;
+  10ee72807a2219bf
+    b474fd71d891f24b
+    ""
+    b6
+    a2
+    fab55a01a7ce028e;
+  5d1563259f9eb53b
+    571ea629c54d57dd
+    ""
+    2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb
+    b690481d25e3f847a804a19814c1290205ce9cbb4b61c233
+    87e5815156bfa03b;
+  9fc2712a199e533f
+    a9156308cdec3f76
+    8281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22
+    260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb
+    dc2c2adba08e9ba7418ffc99171134a1581b124c03877cd1
+    220cc3fa8f48fdd3;
+  3b6f5fe836813111
+    5c037ba323fe1dc8
+    ""
+    151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b
+    b8aefb9157f020717f5afd56802e8c489aa69a4ebbfd1a5c4e05ee4dca
+    91762112616e9ad2;
+  09c063c46f88de9f
+    d41e72d7b97e23e6
+    eabdff3bcd211499268878dbf30f1dad89d4b9
+    b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f08345
+    236430169ce67a46cf7a2b31e20aff1d656863550b2cbed9feb213bebd
+    641bc761257b4572;
+}
+
+safer-pmac1 {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    061d742fa0b5e9fb;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    496f756150b24f97;
+  ad568f86edd1dc9268eeee533285a6ed
+    810c9b689daaa9060d2d4b6003062365b0a54364c76c160f
+    659f6109ebea03e4;
+  11896c4794846ecfa14a7130c9f13712
+    0634c9519848a877ff77bf79192a5b50ade5d9
+    169f91020e2bfa02;
+  cd739a3d1f337f29
+    ""
+    bcb4bfd69665cfac;
+  549e6b0d27a4ba23
+    40
+    1e041b274662fca9;
+  85406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    8b6e6d10707bb048;
+  21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbd
+    8ca64eea215c495b;
+}
+
+safer-ocb3 {
+  bef260d7bcda163547d348b7551195e7
+    7022907dd1df
+    ""
+    ""
+    ""
+    c68d1906e4ecf5b7;
+  f7dac5c9941d26d0c6eb14ad568f86ed
+    d1dc9268eeee
+    53
+    ""
+    ""
+    3d2c6b8d272ad1bd;
+  3285a6ed810c9b689daaa9060d2d4b60
+    03062365b0a5
+    ""
+    43
+    1e
+    ac7b2f4dcf701c36;
+  64c76c160f11896c4794846ecfa14a71
+    30c9f1
+    ""
+    37120634c9519848a877ff77bf79192a5b50ade5d9cd739a
+    3d77279a2b3174b4cda74767a200b3ced178c630f4021f95
+    46868129219846b1;
+  3d1f337f29549e6b0d27a4ba23408540
+    6a61365120
+    61f7080cc07df0591d8fa21f2dd88374d8cde8e160ad1099
+    7a21635c6d62c9269029df3e6057acc87638f508046733d9
+    73f22628de757cf0ae4533014abe1e212cac8e7dc8d6c704
+    b0592f0672c25ce4;
+  ff61cdbda3b3e9878731ebfedd4705e5
+    05da1435dcea
+    ""
+    a7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    14072ae825472e9f41b4d3608dcb28f76c38dba433fac5ac21885d3590
+    70c90062488d754e;
+  21b7f65b000961040ef2f9b2fc5fa450
+    727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb1
+    8ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93b
+    c67a74b2d9ab0e76d4e12ca3f67a21b36b96f6e153876245f24fb860d4
+    da1bc80ce1be6ab3;
+  f4f2aad2605faee2
+    b03fb648e27f
+    ""
+    ""
+    ""
+    5c58fc2737aa84b2;
+  ff63102758fe2b69
+    ac26afa33498
+    29
+    ""
+    ""
+    105063844d7b9bae;
+  b94586306fed5415
+    4f8f28523c03
+    ""
+    d4
+    0a
+    bf73c757de4bdf7b;
+  de1600157846b710
+    ee7280
+    ""
+    7a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea6
+    930c7d41a8b6f15ef14b066dc63cdddb1be6e934551bd1c1
+    e40d324516b9b127;
+  29c54d57dd2d42f7
+    0800df9fcb
+    aca48b77dba189196d1ebba10b0467cb9fc2712a199e533f
+    a9156308cdec3f768281e040a9b9a222bd689aef66f5306c
+    1d2eb8f21e5e62392ffee6754fba853ce71e10ac506c9e4d
+    57dec2089ee8cd44;
+  eb0c6b08ac8b0a22
+    260c571b4a42
+    ""
+    bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037b
+    1cd78bee247725a186a54ff71232b3197dbad5c69ea23db3dac003d3f6
+    3d21f3e8ffca5e4d;
+  a323fe1dc8151784
+    873f0eb5b647
+    da6794c18b5337685a96ed65b9aca338527ef1
+    9b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878db
+    59da4376f65bf4bfdf59cca15597d76b021a759e71d20b382f587e1a74
+    ff7e706dfb3aadc7;
+}
+
+safer-ocb3-mct {
+  16 fcbfdf66d89efaa3;
+   8 7acb5078112677aa;
+  16 baa9bc81de93;
+   8 ca467bdf7b39;
+  16 f6659aeb;
+   8 1b3348ec;
+}
index 8c42f58..5992634 100644 (file)
@@ -1 +1,463 @@
-### No tests here.  See `safer' instead.
+### Only modes here.  See `safersk' for the blockcipher test vectors.
+
+safersk-cmac {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    9ba8f2c1b6cfeb77;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    37dcfeffa9f5744b;
+  ad568f86edd1dc9268eeee533285a6ed
+    810c9b689daaa9060d2d4b6003062365b0a54364c76c160f
+    05bf5b261fbd88de;
+  11896c4794846ecfa14a7130c9f13712
+    0634c9519848a877ff77bf79192a5b50ade5d9
+    0ee50cf1eb23cc77;
+  cd739a3d1f337f29
+    ""
+    975807086410e7e5;
+  549e6b0d27a4ba23
+    40
+    b5b26235e6a34f78;
+  85406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    b98cae59f10f22cd;
+  21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbd
+    d85e3e89ce01118c;
+}
+
+safersk-ccm {
+  bef260d7bcda163547d348b7551195e7
+    702290
+    ""
+    ""
+    ""
+    9a4a828c;
+  7dd1dff7dac5c9941d26d0c6eb14ad56
+    8f86ed
+    d1
+    ""
+    ""
+    41f68f45;
+  dc9268eeee533285a6ed810c9b689daa
+    a9060d
+    ""
+    2d
+    7b
+    acc985bb;
+  4b6003062365b0a54364c76c160f1189
+    6c4794846e
+    cfa14a7130c9f137120634c9519848a877ff77bf79192a5b
+    50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a
+    aa629c01eb3b15ede6c2e4366419b5e5f40469d538d373ed
+    a136e047cf4a68b0;
+  6136512061f7080cc07df0591d8fa21f
+    2dd88374d8
+    cde8e160ad10997a21635c6d62c9269029df3e
+    6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505
+    1c34203b3161577c889c9db08bf34b20a3e5da5857a94d09e73edf7210
+    953f9c31334dfede;
+  da1435dceaa7b1cc
+    49ae1d
+    ""
+    ""
+    ""
+    b5ad4f52;
+  50c38201a894476b
+    3f102b
+    75
+    ""
+    ""
+    f69a75fd;
+  2eb9529533966f27
+    043eb6
+    ""
+    21
+    14
+    72b85363;
+  b7f65b000961040e
+    f2f9b2fc5f
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3
+    ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54
+    b65cbf23154b9798e5250e96f51659df1024bf6b0ffd859b
+    9616166b0ae5320f;
+  efc9a38378c5b93b
+    f4f2aad260
+    5faee2b03fb648e27fff63102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee
+    6d0ac961eed6fa2cad9f51d293bad02ecc7a8effe3511cb9aae4935bbd
+    96dee0d7ba957d24;
+}
+
+safersk-eax {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    ""
+    ""
+    ""
+    9bc0cb5650ecbe0d;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    ""
+    ""
+    ""
+    04655ac860f00c4c;
+  ad568f86edd1dc9268eeee533285a6ed
+    ""
+    81
+    ""
+    ""
+    23de91600ff46611;
+  0c9b689daaa9060d2d4b6003062365b0
+    ""
+    ""
+    a5
+    c2
+    a47b7c287e2aaccb;
+  4364c76c160f11896c4794846ecfa14a
+    7130c9f137120634
+    c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0
+    d228821b771c225b34c32f1d8def6b1638a580259d14966c
+    c2d9f9bcacbf1796;
+  591d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62
+    c9269029df3e6057acc87638f508046733d9ff
+    61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c3
+    56e9c63e94a3e304fb0204a14ddce527063e43cbb59e5f4cdc5ca4c9fd
+    3c18c6748c8d3efb;
+  8201a894476b3f10
+    ""
+    ""
+    ""
+    ""
+    a30a7f2fdcfd304f;
+  2b752eb952953396
+    6f
+    ""
+    ""
+    ""
+    a3921ada1effe4a9;
+  27043eb621b7f65b
+    ""
+    00
+    ""
+    ""
+    b21c194c92a0e99a;
+  0961040ef2f9b2fc
+    ""
+    ""
+    5f
+    9a
+    ec1dc651cd6f903d;
+  a450727a9b542cde
+    52ebfda19d0ccc52
+    0f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090
+    c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2
+    74b140592d02d6e569a0f917fd935c2c4ff50e612a765163
+    69c737214ba7d4ef;
+  b03fb648e27fff63
+    102758fe2b69ac
+    26afa3349829b94586306fed54154f8f28523c
+    03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563
+    bde1b3e1c19bb966ee531fa15ec929593e29aca538a004e1a98e6776f2
+    ed2e0c47042a787f;
+}
+
+safersk-gcm {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    ""
+    ""
+    ""
+    27b0cf2d5823652b;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    ""
+    ""
+    ""
+    284a84e5a061c638;
+  ad568f86edd1dc9268eeee533285a6ed
+    ""
+    81
+    ""
+    ""
+    e137081a8189b00d;
+  0c9b689daaa9060d2d4b6003062365b0
+    ""
+    ""
+    a5
+    07
+    d1476d790c73fe20;
+  4364c76c160f11896c4794846ecfa14a
+    7130c9f137120634
+    c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0
+    220e383555bc3c1db79dd7946ab1bcfb0c8ae7534e054dfe
+    b9125ab89a341129;
+  591d8fa21f2dd88374d8cde8e160ad10
+    997a2163
+    5c6d62c9269029df3e6057
+    acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7
+    da40ac7ce7efbc6e5a0c8edad1fc6e37707dcd577c2b525173d91c0ee1843bf296
+    7fe1bd570ff9bc5e;
+  b1cc49ae1d50c38201a894476b3f102b
+    752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5f
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6
+    7088301eaa71ebd8aa7357fa70408eff7803127fdaf86f8f64fc46bde4
+    1b6b05d79e3e8a50;
+  c95a97a48030370c
+    ""
+    ""
+    ""
+    ""
+    c202c8435d5db9f9;
+  33d090c54215abd6
+    b3
+    ""
+    ""
+    ""
+    127f007760bb2caa;
+  ad54efc9a38378c5
+    ""
+    b9
+    ""
+    ""
+    8e7eb7606063486c;
+  3bf4f2aad2605fae
+    ""
+    ""
+    e2
+    87
+    f7db784dd6349ec3;
+  b03fb648e27fff63
+    102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de160015
+    7846b710ee72807a2219bfb474fd71d891f24bb65d156325
+    e9a1e4e745d37146bd75efe05e451dbf120fe907a9f5701f
+    59283c69e487ac87;
+  9f9eb53b571ea629
+    c54d57dd
+    2d42f70800df9fcbaca48b
+    77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040
+    65b78f763a328655662a4ef7f9bacfe67e5e07df80edbcc853440ee1f7627d0355
+    38dbad9c5138e19e;
+  a9b9a222bd689aef
+    66f5306ceb0c6b
+    08ac8b0a22260c571b4a42bb8fdb233bfa6a5c
+    fb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784
+    0d4082f666ad6a4d337a93564bc648f4b09e2332d656aeebefd722a7ec
+    4322ea279fd752dc;
+}
+
+safersk-ocb1 {
+  bef260d7bcda163547d348b7551195e7
+    7022907dd1dff7da
+    ""
+    ""
+    ""
+    02524b8ee7329780;
+  c5c9941d26d0c6eb14ad568f86edd1dc
+    9268eeee533285a6
+    ed
+    ""
+    ""
+    aa1f6928e1b81e20;
+  810c9b689daaa9060d2d4b6003062365
+    b0a54364c76c160f
+    ""
+    11
+    07
+    cc863f9f86e79df5;
+  896c4794846ecfa14a7130c9f1371206
+    34c9519848a877ff
+    ""
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4
+    0a622ec626cf3be0c96a8fcabfa824949c81cf57656e3fcc
+    4b897d5463f508df;
+  ba234085406a6136512061f7080cc07d
+    f0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057
+    acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    ceaa0608044abe172e762b8a66a026b6aa231a60e32b8852
+    383b6f426f78e95d;
+  05e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f10
+    ""
+    2b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450
+    e9d6111a98647e1da68ba0bdfb386b3575c20aba3fff9bb7d5e52e5717
+    f432ded708b7e826;
+  727a9b542cde52ebfda19d0ccc520f21
+    5eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6
+    b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff631027
+    58a7612db1435cc3b8b7ab586fd3475674faa6192c47cf940061b38ad0
+    ee64360a85eb7957;
+  58fe2b69ac26afa3
+    349829b94586306f
+    ""
+    ""
+    ""
+    bffcea16dd9830d2;
+  ed54154f8f28523c
+    03d4de1600157846
+    b7
+    ""
+    ""
+    9d9d3268ed1e6af0;
+  10ee72807a2219bf
+    b474fd71d891f24b
+    ""
+    b6
+    55
+    7cc85e98d653ac98;
+  5d1563259f9eb53b
+    571ea629c54d57dd
+    ""
+    2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb
+    69fd708caa761fa04396ba9f94bb916e5a11679b3bad9cf0
+    8c94cf5b2249afa6;
+  9fc2712a199e533f
+    a9156308cdec3f76
+    8281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22
+    260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb
+    c9e3275788dcac045ae1478a44aac8061f02bc7e56e516cc
+    8adfde6b3cd647c5;
+  3b6f5fe836813111
+    5c037ba323fe1dc8
+    ""
+    151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b
+    f1493455c6ef6dfb73ba4b35b25ecef1d967614169fd0db3162575f20c
+    533087817a013891;
+  09c063c46f88de9f
+    d41e72d7b97e23e6
+    eabdff3bcd211499268878dbf30f1dad89d4b9
+    b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f08345
+    f89081f88fa58ddd7f1974ffc3fb676fc8855e74c7b85d6e308e2c3096
+    b0c2845962f040ff;
+}
+
+safersk-pmac1 {
+  bef260d7bcda163547d348b7551195e7
+    ""
+    6dd75ab7922413b1;
+  7022907dd1dff7dac5c9941d26d0c6eb
+    14
+    7f4d03871ad27bda;
+  ad568f86edd1dc9268eeee533285a6ed
+    810c9b689daaa9060d2d4b6003062365b0a54364c76c160f
+    3f48cfbe20527417;
+  11896c4794846ecfa14a7130c9f13712
+    0634c9519848a877ff77bf79192a5b50ade5d9
+    25fb410e71c6553d;
+  cd739a3d1f337f29
+    ""
+    af55847d75152f93;
+  549e6b0d27a4ba23
+    40
+    b24dc9bbdbe4b417;
+  85406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    9e119f41d7bf7b13;
+  21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbd
+    9f8f71cddf2bf6dd;
+}
+
+safersk-ocb3 {
+  bef260d7bcda163547d348b7551195e7
+    7022907dd1df
+    ""
+    ""
+    ""
+    6e456312a40d6780;
+  f7dac5c9941d26d0c6eb14ad568f86ed
+    d1dc9268eeee
+    53
+    ""
+    ""
+    65b5cb090a3f28ae;
+  3285a6ed810c9b689daaa9060d2d4b60
+    03062365b0a5
+    ""
+    43
+    63
+    4e6dc1b24486771b;
+  64c76c160f11896c4794846ecfa14a71
+    30c9f1
+    ""
+    37120634c9519848a877ff77bf79192a5b50ade5d9cd739a
+    fa8d42d4d17056a5cb34c6792272af358e3c7e7b9490aa3f
+    3acb963aa0fc701f;
+  3d1f337f29549e6b0d27a4ba23408540
+    6a61365120
+    61f7080cc07df0591d8fa21f2dd88374d8cde8e160ad1099
+    7a21635c6d62c9269029df3e6057acc87638f508046733d9
+    8cd70cce2aaf4a9ea62faa31d7146087d2b9b47e7992e17e
+    3e16cf32a2faa211;
+  ff61cdbda3b3e9878731ebfedd4705e5
+    05da1435dcea
+    ""
+    a7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    239d7c4c0f2c17577768de8cbedf192d08e82cfc74a587ab5267ee7e81
+    e6f7aad35cceb122;
+  21b7f65b000961040ef2f9b2fc5fa450
+    727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb1
+    8ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93b
+    bbd3b140decdd5e0a63b4a38989e770bedbe26054f882cbf1920fbd514
+    a71d070227d87267;
+  f4f2aad2605faee2
+    b03fb648e27f
+    ""
+    ""
+    ""
+    63e4d0211e0a4daf;
+  ff63102758fe2b69
+    ac26afa33498
+    29
+    ""
+    ""
+    0fb3f4a5cc43406a;
+  b94586306fed5415
+    4f8f28523c03
+    ""
+    d4
+    06
+    afaa82d25e44d4db;
+  de1600157846b710
+    ee7280
+    ""
+    7a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea6
+    bc640b0230973b8be088cdc0f0c18fafe95f13d3197d9c09
+    e42c5b6c0e33d57e;
+  29c54d57dd2d42f7
+    0800df9fcb
+    aca48b77dba189196d1ebba10b0467cb9fc2712a199e533f
+    a9156308cdec3f768281e040a9b9a222bd689aef66f5306c
+    f9f9760a9b9277c4216a7d12c59d78f7cfc3c5fe811f9e38
+    26bd0ba14ccc28d3;
+  eb0c6b08ac8b0a22
+    260c571b4a42
+    ""
+    bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037b
+    35511a69e4039fa87bf9cccdd152453842004258de53166380645f0c57
+    99979d46633f3381;
+  a323fe1dc8151784
+    873f0eb5b647
+    da6794c18b5337685a96ed65b9aca338527ef1
+    9b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878db
+    b6190f6df6109cb3134a517871e360503ace233210255bd503451ccf78
+    b9d9982e2ad6564b;
+}
+
+safersk-ocb3-mct {
+  16 3857e95d746bbe01;
+   8 545057df78fb5ea9;
+  16 c2e0438d09ff;
+   8 36b5c340bd6d;
+  16 5dee93a9;
+   8 8752f8e9;
+}
index 9188749..b03d2c3 100644 (file)
@@ -87,3 +87,15 @@ xsalsa20 {
   be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffce5ecbaaf33bd751a1ac728d45e6c61296cdc3c01233561f41db66cce314adb310e3be8250c46f06dceea3a7fa1348057e2f6556ad6b1318a024a838f21af1fde048977eb48f59ffd4924ca1c60902e52f0a089bc76897040e082f937763848645e0705
   8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186ac0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5;
 }
+
+salsa20-naclbox {
+  ## Taken from Daniel J. Bernstein, `Cryptography in NaCl',
+  ## https://cr.yp.to/highspeed/naclcrypto-20090310.pdf
+
+  1b27556473e985d462cd51197a9a46c76009549eac6474f206c4ee0844f68389
+  69696ee955b62b73cd62bda875fc73d68219e0036b7a0b37
+  ""
+  be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffce5ecbaaf33bd751a1ac728d45e6c61296cdc3c01233561f41db66cce314adb310e3be8250c46f06dceea3a7fa1348057e2f6556ad6b1318a024a838f21af1fde048977eb48f59ffd4924ca1c60902e52f0a089bc76897040e082f937763848645e0705
+  8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186ac0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5
+  f3ffc7703f9400e52a7dfb4b3d3305d9;
+}
diff --git a/symm/t/serpent.local b/symm/t/serpent.local
new file mode 100644 (file)
index 0000000..d7a0340
--- /dev/null
@@ -0,0 +1,992 @@
+### Local tests for Serpent.
+
+serpent-cmac {
+  60d7bcda163547d348b7551195
+    ""
+    837d499a07a2518f04835f42131f5831;
+  e77022907dd1dff7dac5c9941d
+    26
+    db320e0bfa3ebb37c57ea0c60576c393;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    0c9a89126f4cad2192ffa4a7c0ca9d68;
+  34c9519848a877ff77bf79192a
+    5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    324c00f44175151d1a2bf9342cf4ef93;
+  8374d8cde8e160ad10997a21
+    ""
+    829328f2a128fdc7c48a7714a5f66acf;
+  635c6d62c9269029df3e6057
+    ac
+    28d493c79ae17e3c1480c921bf4e6d2e;
+  c87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    63c9c5f2dcd9e476c72dee514b84d6f9;
+  21b7f65b000961040ef2f9b2
+    fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    ca4332a12b4981383e8548d4beacce63;
+  4215abd6b3ad54ef
+    ""
+    51a036a675d7fd48aea66b5fea454712;
+  c9a38378c5b93bf4
+    f2
+    5b8642963edfd3fc3537cf7a53ffdb72;
+  aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    40bbb9860714b5c28a127928704b04f2;
+  bfb474fd71d891f2
+    4bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9f
+    b59d4d54d7846d564c8e65a6ae652a74;
+  c2712a199e533fa9156308cdec3f768281
+    ""
+    9af557733264840dca5e8260f160ffb4;
+  e040a9b9a222bd689aef66f5306ceb0c6b
+    08
+    ca7d2919e279fd3caf61e6ff35bb7803;
+  ac8b0a22260c571b4a42bb8fdb233bfa6a
+    5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    33036f52f479780af315c2de95e9dc86;
+  b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    8ef0d030ddb7bd4c700e15efc563f5cf;
+}
+
+serpent-ccm {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9
+    ""
+    ""
+    ""
+    dc912161;
+  941d26d0c6eb14ad568f86edd1
+    dc9268eeee533285a6ed81
+    0c
+    ""
+    ""
+    5499b369;
+  9b689daaa9060d2d4b60030623
+    65b0a54364c76c160f1189
+    ""
+    6c
+    52
+    ea1be4b3;
+  4794846ecfa14a7130c9f13712
+    0634c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    1d58fa7d358e6d619c942eb0285e79dbce0aee4e671ef19021d80ece2710a144ae511c8f973ff2f06d8c6f0cc2942c5e
+    18d3a010e72c36fd75d6c2379c947385;
+  05e505da1435dceaa7b1cc49ae
+    1d50c38201a894476b
+    3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0c
+    cc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb6
+    7b48d588bb1af8f0eff0e80c692d51010b7f3b1d6655b2e18c1241862819d1a25631053d5eea17417a5b5c928d32eb181043df7dde
+    8e0224854ea7153f52e096633776fc97;
+  48e27fff63102758fe2b69ac
+    26afa3349829b94586306f
+    ""
+    ""
+    ""
+    940a7ecd;
+  ed54154f8f28523c03d4de16
+    00157846b710ee72807a22
+    19
+    ""
+    ""
+    99081a6e;
+  bfb474fd71d891f24bb65d15
+    63259f9eb53b571ea629c5
+    ""
+    4d
+    95
+    67001f0c;
+  57dd2d42f70800df9fcbaca4
+    8b77dba189196d1ebb
+    a10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c57
+    1b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da67
+    59c14232f48220ad1f3966d9d52d9b9b9ae739c4fa6a690c445716eb73951b229de71b78e83b03ac3401f58adaafd1bd
+    2f3304e936c26f3998308ceb36022d3a;
+  94c18b5337685a96ed65b9ac
+    a338527ef19b09c063
+    c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e
+    7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d079839180
+    99574f4879d83e020a18b5133a5c97d0c7fc72a37e787d16e6d8e959df0cc8d9b62cb8f54d74208c140f13abce1dc058829dc0bd01
+    0dd232275c64fcfc8b5d0fc2bf948ebe;
+  5da08da3aefc5f85
+    84b7c5e617669c0f16e398
+    ""
+    ""
+    ""
+    e6725fe0;
+  15d4e9cfce3ed1ec
+    df3d264a7f16cb16c2e815
+    f4
+    ""
+    ""
+    ad7b2fe0;
+  22cdf0c8e30308be
+    3c31e6bc58c0b7cadcb658
+    ""
+    b9
+    6e
+    f2943ec1;
+  70e47479a684b5ae
+    fa69a4cd52147ed12c
+    a986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae98
+    5511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608
+    e1e63326b5795e04360ba24658defb1216302976c9a921ea18adf8b1723a91a6a8095e1d2b49a9e48cd603dd707d881e
+    1b69dccc1f344f1ca9d04a725b5481bc;
+  fe95e81c2533e31c
+    9c1a9851bc2810d858
+    cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a7
+    7456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0c
+    61ad6fd5019e1229ae86cd9840357861473a647ec3a939e9e68113c289e1f917e658651cf2217aa46837c404632b1feabb16939df0
+    6881e216ee5fd2da76529e9019027188;
+  ae9ce021a5f1fa4ffa91544485f1a1258b
+    2b9b8f0911e32d65cc1770
+    ""
+    ""
+    ""
+    6679e4e9;
+  a18cbfe6effd1ff6778554acf1270485b2
+    03a3c1c4c967c0a458cb94
+    8b
+    ""
+    ""
+    c6460f74;
+  dd409b687fa3a6827b480aa3a4c84cef64
+    f6c9b53bf8f957f4b03cf4
+    ""
+    3e
+    83
+    b85403e7;
+  89957f9a3e8128f8743d16687b7bb8deb9
+    bd205b70e04c091d20
+    5cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397
+    abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107
+    2651fec0d8fcff49d1f5df59bf41bd0c6fef0e7d49c915bd20f775ffd8af47be58f20ed9f7a5709978e5af892ff52ea6
+    8247a18e44f3a38840a6c98db85a10e3;
+  c8e7d715a92add9589d1f5c054b2d98351
+    4605ec590294a319b9
+    802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee
+    1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44
+    f060d6a432737be40681731d964ae4310460967fab931db70fd394d02c4f2691b14891986837af0342d9d01e688498e161ce84598a
+    6db772689af25f8ebba8ad1966dfa1ea;
+}
+
+serpent-eax {
+  ## Taken from Secnet, with thanks to Ian Jackson.
+
+  233952dee4d5ed5f9b9c6d6ff80ff478
+    62ec67f9c3a4a407fcb2a8c49031a8b3
+    6bfb914fd07eae6b
+    ""
+    ""
+    1271ec1e68330eb461a96d3a3a7a2707;
+  91945d3f4dcbee0bf45ef52255f095a4
+    becaf043b0a23d843194ba972c66debd
+    fa3bfd4806eb53fa
+    f7fb
+    1c73
+    67d3db493a1f7b054ececa2a2cf37ee6;
+  01f74ad64077f2e704c0f60ada3dd523
+    70c3db4f0d26368400a10ed05d2bff5e
+    234a3463c1264ac6
+    1a47cb4933
+    2439712b59
+    b13982351ba05b25bb2bd3b95df62d73;
+  d07cf6cbb7f313bdde66b727afd3c5e8
+    8408dfff3c1a2b1292dc199e46b7d617
+    33cce2eabff5a79d
+    481c9e39b1
+    f1d718884b
+    e94b29e143a264b54e283ca9e439c90d;
+  35b6d0580005bbc12b0587124557d2c2
+    fdb6b06676eedc5c61d74276e1f8e816
+    aeb96eaebe2970e9
+    40d0c07da5e4
+    5936db85df31
+    199ba3556a5d5eff1964a6befea0d950;
+  bd8e6e11475e60b268784c38c62feb22
+    6eac5c93072d8e8513f750935e46da1b
+    d4482d1ca78dce0f
+    4de3b35c3fc039245bd1fb7d
+    7a3a7997ee349b57152cc43f
+    723903a85b09d86456315ac0d9180724;
+  7c77d6e813bed5ac98baa417477a2e7d
+    1a8c98dcd73d38393b2bf1569deefc19
+    65d2017990d62528
+    8b0a79306c9ce7ed99dae4f87f8dd61636
+    73548ffaf45d2617eb25ad1dffa1842083
+    6d48394d5ef2cd2e0e30cdd2f4c52d96;
+  5fff20cafab119ca2fc73549e20f5b0d
+    dde59b97d722156d4d9aff2bc7559826
+    54b9f04e6a09189a
+    1bda122bce8a8dbaf1877d962b8592dd2d56
+    e8bd1c6fe47df149a141ce813b0c1239542e
+    c4cbf7b3968388d631e6f4ffe86e14e7;
+  a4a4782bcffd3ec5e7ef6d8c34a56123
+    b781fcf2f75fa5a8de97a9ca48e522ec
+    899a175897561d7e
+    6cf36720872b8513f6eab1a8a44438d5ef11
+    e4a9d72847d437b85f10b7daa46f1e00e350
+    9af0b97961c39dfbb70170b6c4cadbc1;
+  8395fcf1e95bebd697bd010bc766aac3
+    22e7add93cfc6393c57ec0b3c17d6b44
+    126735fcc320d25a
+    ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7
+    83d69403eae9386b679daeaad2951465f8ddf9be1a
+    ffad1c5fef072f8b48bd58c07fee3d83;
+
+  ## Locally-generated tests for edge-cases.
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    47f4f974dac8fbccb2d85c4dd030ecc2;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    fdd1a67df6ef4962c0e07c3bcb258fdb;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    dddced0e626e1a606ad6150f981231c4;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    93
+    994b5c972bc7d85771220863405b62be;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9
+    f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7
+    080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61
+    82f5aab367d2f92bb06cdbdcf3b840fa03775f8473bc2c7923d06b0d264679c2bb8ad3a0b4008946198caa858ac3035b
+    4be2dd26de2bb142d08d2e80ff7e1556;
+  cdbda3b3e9878731ebfedd4705
+    e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    4a2f0f21a4c240fcebbda1500c1c87193c1100ab9922b6c02b6200eb6c4c166ba715f09ba95ff7daa0a49a92139b1fb7785198c3cd
+    7597b3928b3811ad02ba9c380fc053b7;
+  5faee2b03fb648e27fff6310
+    ""
+    ""
+    ""
+    ""
+    0a85bbdf824c6fd51bb56934219a44bb;
+  2758fe2b69ac26afa3349829
+    b9
+    ""
+    ""
+    ""
+    8b3c4c5ef77b2b25cd78f8e7ee1a1eeb;
+  4586306fed54154f8f28523c
+    ""
+    03
+    ""
+    ""
+    9dd8b376a786caa020f631ec33e8adee;
+  d4de1600157846b710ee7280
+    ""
+    ""
+    7a
+    9d
+    66d221c6542adab014cde389a8375271;
+  2219bfb474fd71d891f24bb6
+    5d1563259f9eb53b571ea629c54d57dd
+    2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222
+    bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836813111
+    d70c3fe1525edf6975dd3ec110f44d66ee38812bee278632cd476e9571d90ea3a4181e472841e699acbb613172b3c8d9
+    cf949b9623f6027249246ff3914f4c9e;
+  5c037ba323fe1dc815178487
+    3f0eb5b647da6794c18b5337685a96
+    ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89
+    d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d
+    bbeb0d455e42b31743e6b1f62e7a8beb05b6579140f9523b441f1523fffd56799ea74a815f64cd65fe2d912c0ac88a42d668020ad4
+    aa19b7bc58fb57f2cd072ed13f7a22d1;
+  30ce2f1fef6ef315
+    ""
+    ""
+    ""
+    ""
+    e071f4b5be472b5d27a62d3b59de4076;
+  d0798391805da08d
+    a3
+    ""
+    ""
+    ""
+    9700bb529c726f7f9383103afde5c072;
+  aefc5f8584b7c5e6
+    ""
+    17
+    ""
+    ""
+    beddb35cd6ce26eeccd01fc49467f581;
+  669c0f16e39815d4
+    ""
+    ""
+    e9
+    89
+    a6ea652052db22889858bba51b743f77;
+  cfce3ed1ecdf3d26
+    4a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98
+    ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b009
+    c343474bde0f534fb167d4f0f45dc029376218f83a54b3dd22eaf08ceb381357ae3c3f73e48d26775bbb3d09ea1300c2
+    9184a5120a75b987ebf1c111ee0f7fe0;
+  51f284649016ed00
+    456331854bc78bf43966eb0cfa9138
+    ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb82
+    4173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc5
+    8a5f8d241fd8edabb3447134fced691a560ffc16eb35351f299055d61c65a9d016a8a2aecd321e2aaba5be088bc4e787d23279d3b9
+    2d94ce868ac29109422a40835e92df30;
+  97f56ccbb2f294b38766fc69f6a9f2c094
+    ""
+    ""
+    ""
+    ""
+    cc3b89f1e518665f325656d16078b115;
+  5ffd505003cc0cae9ce021a5f1fa4ffa91
+    54
+    ""
+    ""
+    ""
+    77f9efcf277f9618606fd47f5233bb79;
+  4485f1a1258b2b9b8f0911e32d65cc1770
+    ""
+    a1
+    ""
+    ""
+    4d91889c474511f47711a00d22a37021;
+  8cbfe6effd1ff6778554acf1270485b203
+    ""
+    ""
+    a3
+    f2
+    db79e93136fbbcb2d167a14005e3e4f4;
+  c1c4c967c0a458cb948bdd409b687fa3a6
+    827b480aa3a4c84cef64f6c9b53bf8f9
+    57f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac
+    8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef340153
+    242f387588ee5c723abeac99f710a02c29c5d9420475d5c81cd7840cdb9c965b2357c9fd6cf4ed18247daf5e5b4908d6
+    72aa25cd54aa0ed7bb78fdf9d491547e;
+  9c51d2a90bbf7f1bfc338ab0ef5746ea8f
+    dcccd213e33f7e8a5718fd25014107
+    c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7
+    ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7ab
+    2ea09fe497954fcc5ff649f0c72b229294018f6d69846e4d55b35fcf561d6d73e36fd253241af102f1a5beabca9f878898bebc3c38
+    018ad589b2a12c05238a52773fd66463;
+}
+
+serpent-gcm {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    b7a5e3afee9d6b5d3272a42db95fe058;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    5a3f93b2c28c3208f3f470a28ded0981;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    31b6ec116273e033816b5ebeb8198b1c;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    82
+    1edf5ba454a8cd5ef0aac6153800a101;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9
+    f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7
+    080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61
+    08276a3d1fd2638903bb85fd5ad5b3abf64d1e384ad5262501e198e697c210d778ef1ca2cb78e3fc462d18daaba7ee12
+    75eb776d709e756036210b8d85056fdd;
+  cdbda3b3e9878731ebfedd4705
+    e505da1435dceaa7b1cc49ae
+    1d50c38201a894476b3f102b752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33
+    6cf5fafa1f1b67aef17c51ecd4cc8807863bb47816d9416eee45e144973c6bfe325b1dd7b29af06a4d9b0e2f993127dcbf33e8075f35781fe7
+    8827e78f2a8ba21a12f6c4078713d83b;
+  d090c54215abd6b3ad54efc9a3
+    8378c5b93bf4f2aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee
+    72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b04
+    11687e1abefb35846b4c37d820220610a076a589e33bdc58b8b9f4f5318a945421139b3122e26578e3d34e00ab2cb88a0de1590b46
+    75d611a4d23fc1cc399cb1d06475c400;
+  67cb9fc2712a199e533fa915
+    ""
+    ""
+    ""
+    ""
+    2e79ef91df0515538a3bf641867668d4;
+  6308cdec3f768281e040a9b9
+    a2
+    ""
+    ""
+    ""
+    4a3d8a26dac3498e97ec445243d6073f;
+  22bd689aef66f5306ceb0c6b
+    ""
+    08
+    ""
+    ""
+    c47eae4dc6e8e34fd594bcf425c93137;
+  ac8b0a22260c571b4a42bb8f
+    ""
+    ""
+    db
+    08
+    d328c14d09ea87f05101640b5c19ec06;
+  233bfa6a5cfb0bad7d95214a
+    de49cb3b6f5fe8368131115c037ba323
+    fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6
+    eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f08345
+    681e86e5aebd4a9648b78daa6bc86d34de3970fa7065f26789d65cb8d0d05639849b612fef76214315948d44f3e9c512
+    2a4f1ff8cc104ded9d693f28d62396a3;
+  5b663e4ee1315f3c8f2aebfa
+    921451dcd1af5813b70d30ce
+    2f1fef6ef315d0798391805da08da3aefc5f85
+    84b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684
+    cbd8037fa6cca0d3c5d760f9775d6ec6b3349a80089425f3a72f47fa138d41ddb7d165fdf2df4d5ea97d430b173363a87cf9d61ef829127ba7
+    f2f7d0abeac736dbcb17c8b11a614ef5;
+  b5aefa69a4cd52147ed12ca9
+    86981a874498ad0abef8bc4fcb70e2
+    7e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720ee
+    f9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d8
+    78aad8dbb0a294e0d23f61421d9adf39e537651cf5d91bc9e815307a021e916467f1abae1cf7eb09aadf42f053f6c9dbb099b7587c
+    f40974b1334cf4c25e29bc26f608bf94;
+  58cbbc8424d126b8
+    ""
+    ""
+    ""
+    ""
+    65a882a10602424ef433579558fd91db;
+  07e6daa089c3f909
+    9c
+    ""
+    ""
+    ""
+    67a19a1d408be278d46cb09c2d09e5ca;
+  5ffb824173d7634c
+    ""
+    04
+    ""
+    ""
+    af4590dab6b84c9ab769597a6075bb40;
+  226f30cbb7f0e4a9
+    ""
+    ""
+    73
+    19
+    ee176a9eb69f35199805f8c19b5061bb;
+  a8cd190107314717
+    a77456f3ff669c732b58db8f48af65f7
+    cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91
+    544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd
+    bcece9311f7669d6f744b547aafeba06c7cb05e623325f183ec1c0b24424f612b10a539f684fd1c0730ee75e5deb2b55
+    d6c09aed972bfb56ab024c80fa114965;
+  409b687fa3a6827b
+    480aa3a4c84cef64f6c9b53b
+    f8f957f4b03cf43e89957f9a3e8128f8743d16
+    687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2eccc
+    fd90ce8763bd7ad21f288077677eb3cfee48137ffe89d5c5965b3d99592896c4eb94b6573c1610d266609da17e3192a833bddc1a656e91b4f0
+    87a7ea3dc29335c676a2d8453d5232ec;
+  b44d65bad397abfa
+    f529ee41cf9a05c7efedef3401539c
+    51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c0
+    54b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe
+    d29ece81f1d8523540fd3e4edae0f717730b301f05f3c9fae128581349a2740ae49266ed8d83a2216072ed232e280163b9531f80c1
+    9f123aa15e25f65aeda0a8c05855c696;
+  079753ee1a957eb6d6699e6b7ea2725cb2
+    ""
+    ""
+    ""
+    ""
+    0d19fefb39f9d5ca47305f578da4c2a6;
+  dac07ecde95759ac46fee6dda7abc8ad68
+    da
+    ""
+    ""
+    ""
+    33e9c876994b5d473cee7028bd8bc422;
+  ac90cfe22d2f1f2968cc42fa8b669ed3bb
+    ""
+    35
+    ""
+    ""
+    b5f2eefdbd65dad3c85637c4644d81b8;
+  42a9cf44bbc8c6254d980398bd94e66eb4
+    ""
+    ""
+    56
+    a1
+    41f9c05ae9ec028487faba6297d754aa;
+  3d405e51881e99027b8ab9aea3ccf860b0
+    009740763d96836c5f87b95460938de1
+    288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c3680
+    0d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f
+    62a4e874b9bed58dfa604492bb7d314c941a359fb4704211a03bb5efb5bd1ead5f4bc209c9ed2ec55945e542da07de30
+    9ab10e04cce4cdb21816a452838e207e;
+  834a06148f302c3973accd56f6f24e3395
+    8b8c2e2352fd61e4fa8fec81
+    6ac861a8b33779f09e7a10fc02a8f48afa3080
+    ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fd
+    6be1ebdac5a498d5c1005189710616d5317726377ccdde02d771a44d9127704c821f1056a1079d34e742ebfdfd11ef3aea46b18655bb2ffe88
+    fd98fa8d62a384d07a991fb3caea3398;
+  e2893232a9f81d14517ffae475f6b94a43
+    a67b3d380d2f9aaafe2dd721c0095c
+    8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785f
+    e426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a
+    100ee38a4070af0c2e7ea43836fcfa78a65278a09ab122bdcdba11d93b63c2965341b19ff4be55ced558fa76d5c3fcb0227e037572
+    cec6a5923cedad5ad0bc6551a039ed2d;
+}
+
+serpent-ocb1 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26d0c6
+    ""
+    ""
+    ""
+    686b0aac51a25d6f2878b1e50e2badbe;
+  eb14ad568f86edd1dc9268eeee
+    533285a6ed810c9b689daaa9060d2d4b
+    60
+    ""
+    ""
+    2811539055c7b5c0e10cabfd66d63d09;
+  03062365b0a54364c76c160f11
+    896c4794846ecfa14a7130c9f1371206
+    ""
+    34
+    b7
+    736d9cb5d0427f0eea7a387136323745;
+  c9519848a877ff77bf79192a5b
+    50ade5d9cd739a3d1f337f29549e6b0d
+    ""
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    c3b13eaa510c580acba8cba253b30f944b369f12002ddefee96ff13f3e7daa0e9836f355b08a055f75839883f3ae65a3
+    81f7d94ad9ffd90dbfaef2d3643f1470;
+  6057acc87638f508046733d9ff
+    61cdbda3b3e9878731ebfedd4705e505
+    da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5f
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54
+    6f6ee0f2bfb91b2eaafde0609efb27f9df091d396cc5932c67c3989439a21fd0528a27da02e746de3bd96e6692f8bfc8
+    05aeefe7a4a38c082ec19f1ab2404541;
+  efc9a38378c5b93bf4f2aad260
+    5faee2b03fb648e27fff63102758fe2b
+    ""
+    69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9e
+    2fa135d2df5aa9ed43e094bba67d692edefd217d7d8f2c64a0f8a2c728176ddd7e699e8ff6681e2508ab05b1014bf461fc21d13f14
+    ba576b55bfc099c9cf4db5c28e90b761;
+  b53b571ea629c54d57dd2d42f7
+    0800df9fcbaca48b77dba189196d1ebb
+    a10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b
+    0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da67
+    ee27f377eff38f2464b289b25dee0a73b9a803fbf821ec328a488dce759e240625a7b3103d49c590858da2771988d0c66c21f12884
+    54ef913069c3dd1c9685f2472b7fc3f4;
+  94c18b5337685a96ed65b9ac
+    a338527ef19b09c063c46f88de9fd41e
+    ""
+    ""
+    ""
+    c4b88fee21ecbc1ffbf6ea083a080716;
+  72d7b97e23e6eabdff3bcd21
+    1499268878dbf30f1dad89d4b9b12012
+    e4
+    ""
+    ""
+    8e5107d4d70c8a727e44b79fbce267ef;
+  713df46795630e7952d22bb0
+    2d7100b8b649377d20a8f083455b663e
+    ""
+    4e
+    f2
+    fade84801d77de290eb960862c98d943;
+  e1315f3c8f2aebfa921451dc
+    d1af5813b70d30ce2f1fef6ef315d079
+    ""
+    8391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e303
+    48a4a77a5651db3c1dd8baae2ce157c1411d1e70c22826da41446890d00ef14467c0439f1f0d10ed95ab8ee0f624f64c
+    d2c05303138ae9ec11f3320c4a9fc1fa;
+  08be3c31e6bc58c0b7cadcb6
+    58b970e47479a684b5aefa69a4cd5214
+    7ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9
+    f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908
+    402444f7ccf9e0aa13173b33afe0bb1e38c233ade7ff56f92a24bd8d17cb137ad49475b39cf3c34a56d074faa7449405
+    67924f31b67c3fc19ed79b5df55e286a;
+  445608fe95e81c2533e31c9c
+    1a9851bc2810d858cbbc8424d126b807
+    ""
+    e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3f
+    5fee9263e96affb3166ef4f393ad28c9baac39c0bcd021025d930e9c4ae105ed386f4664d28857b8d29c83f377590385c8252bbbac
+    3ec53f10d421ae13299f734e4c33c5c4;
+  b90e1721b730374ffc9bc597
+    f56ccbb2f294b38766fc69f6a9f2c094
+    5ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6
+    778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f
+    613d48844e3ff8fd0fa43fe6356b519c8e851d8b70f90d4bbb82905ac14e77e4ce53fb727b8c408bda29425856f06d722308628b27
+    2e3f1daa8e87557852dbb4d5a9f0e978;
+  9a3e8128f8743d16
+    687b7bb8deb9bd205b70e04c091d205c
+    ""
+    ""
+    ""
+    595360839f7632d4470fad88b88bcb17;
+  dad9e9a79b1abf91
+    b0851e5ca605ac845139958701167750
+    8a
+    ""
+    ""
+    446bce84dfdd94177e90e9bae6bfc1c5;
+  15dde524af3e2bee
+    0646541a42c2ecccb44d65bad397abfa
+    ""
+    f5
+    d6
+    1c8be9521e25a947fb8bcea3f3e095cb;
+  29ee41cf9a05c7ef
+    edef3401539c51d2a90bbf7f1bfc338a
+    ""
+    b0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b980
+    3f68fd5d2677fb15a8c99b65baf1e8aedb5a71b8756fd5326567128473762ae4498809325d9f2d1a031e58b9f181266f
+    723cde60d1e536a1e076650f3261f473;
+  2068a9f891bc5ba5
+    afabf8c3122d12d7ff3c41122d70d17d
+    4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68
+    daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9
+    9f5e2d1dd5454687873145ef6970fe06636195562fabbad9a3a76bf0dce03732a32ed87a326e3e8e9b1c5d0f41bcda54
+    802ccadfb7baaf0b6cf6579eca51f720;
+  aea3ccf860b00097
+    40763d96836c5f87b95460938de1288c
+    ""
+    69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308b
+    fb81a3b2a097da78f981bbb53b2623f6271fd097fb6d126851ff942038904f0fb2cf4e265448c30df6a94559ae260d00a81af76545
+    d9290c98d01f6032bf110b61657e165d;
+  a60076817523bd2a
+    bf1261b089d8f23a9c2835076a23faac
+    2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa
+    8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578
+    cee153d3db504d8bb1d7050124952705e0eb9150cd5806e0b40f104eb15167512699f11b129604f7f36915159f592171dbb89b5604
+    5c96b8868aafbcb195e23f9335d73535;
+  c8ec4837898a92142b5b0677da1ac27311
+    7b45bcfff5d5f8b6fde2893232a9f81d
+    ""
+    ""
+    ""
+    b71d7a6b4f83e6276400173ddaeb0be8;
+  14517ffae475f6b94a43a67b3d380d2f9a
+    aafe2dd721c0095c8808847689211450
+    ba
+    ""
+    ""
+    7c5df02df2e106fed4414626ae5b5315;
+  8095ffab1eaadf66fd22ac1976063e113a
+    b61f813e28a1397a7974a1d7f4220c78
+    ""
+    5f
+    86
+    6a7d0527c06c781aea0a6b0389048b08;
+  e426a5a0e80f678d404147842941feeffd
+    c2eb44dc8c0d5e8f444f7f4e0c893959
+    ""
+    b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3
+    b6c017318dda6d2389ab13ae89849c2944a151d982f0490074e38594c6f6a819c3ed133cca4493d84434228645dd47f7
+    6eebac1b2230b2fca6daefff666d4cd3;
+  ab6cf8556b7aa776945948d1b8834df219
+    6c92ec1718dcdeee0d52d9539726d281
+    0391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa
+    4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0
+    b1493269b6bc9b0c2a95e3b26c0df50fd48c5505c85d0f1cc545cb8ee4b9aa1917e71d2f8628a3b38d6282fa23d4021d
+    a6fe44618a21904fb885560b2dca9e2f;
+  a9aabb6c4e3c3554f8fb1ef61614c27029
+    5dfc0ca6551ca4bdb75359f91cb9d921
+    ""
+    056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3d
+    5ad848d7910c43775ad95850550e36ed4f51a9180a1558752ef9043d53d15b7328f82cf31dd6e89fde07890019b7cba632600d6c87
+    58f508482940235912a6955d16d75ac4;
+  f6c2b3fac7cbcf96523d4723f91801325e
+    b8553236651c96788d73d192ee53b3f3
+    ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837
+    bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b5
+    8450286f64f58e3f5cd1d62c28db59591ddf05384d3eaf824acdd8febc6f56595d91eb32d608beabe8f31117a5b42e8d38863be19d
+    cd0ddc15fdb0b43ab9c1da27dab961e9;
+}
+
+serpent-pmac1 {
+  60d7bcda163547d348b7551195
+    ""
+    86802543a1d8ca8f65b1bb3e0d31d221;
+  e77022907dd1dff7dac5c9941d
+    26
+    dbe75897dbb97ea7a0545fe684170ede;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    13c3430e93df53d7da7833282eee3c25;
+  34c9519848a877ff77bf79192a
+    5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    3af04cadceba44ec5a6897e499e82f51;
+  8374d8cde8e160ad10997a21
+    ""
+    1d72b61bfec2412d29f3f0ecad5d04c8;
+  635c6d62c9269029df3e6057
+    ac
+    3441e6813346f41a8f780f9921ccf0ea;
+  c87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    297ec48558af83ac8ebcb3e442fcfc8d;
+  21b7f65b000961040ef2f9b2
+    fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    1c6db42246e98e9eaa43a287e5c7161c;
+  4215abd6b3ad54ef
+    ""
+    e79dc50690f53356f567c3fe1845e31f;
+  c9a38378c5b93bf4
+    f2
+    01c74df5d34de8442b6e0dea2f43cfcd;
+  aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    e36a0ed637bc357b41d7ca57834fe1cd;
+  bfb474fd71d891f2
+    4bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9f
+    1f2abc9e954b1e7d282ef8c3ee00fea4;
+  c2712a199e533fa9156308cdec3f768281
+    ""
+    b498a64086f85b98d362950e079b3624;
+  e040a9b9a222bd689aef66f5306ceb0c6b
+    08
+    febb2df39da1126d67fa08e337c430d1;
+  ac8b0a22260c571b4a42bb8fdb233bfa6a
+    5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    7f8f5f88f99a29146523eec2910448f5;
+  b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    0c21a0dd3a264c1ef7cfeebd6aa8c2c8;
+}
+
+serpent-ocb3 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26
+    ""
+    ""
+    ""
+    4f7cf8f6ab514ac1f3727f957c772859;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9
+    06
+    ""
+    ""
+    49cd7a3bc7a32c2f5ef6c4097d9f3e48;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a71
+    ""
+    30
+    22
+    1105ad05b7e04476b4c7a746a45538eb;
+  c9f137120634c9519848a877ff
+    77bf79192a5b50ade5d9cd
+    ""
+    739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    db5d464d5b9a3659805cb7a3e720721f7b6963be1c93ca3d5ad39b5bfb7d12aaedab640a6d098a0561198d05cd9fda2d
+    25430830a120e8e713128afa579ce1cc;
+  21635c6d62c9269029df3e6057
+    acc87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    21b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a480
+    402dce04d49efb3aff4154a91ab4117d865b8c1e894e3e0170dbf421ca1a92addbe8599f92ffccaf4a96bf1ea5fe54ee
+    00589c1be04b5aff3a9eba045c305801;
+  30370c33d090c54215abd6b3ad
+    54efc9a38378c5b93bf4f2aad260
+    ""
+    5faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    48023bca0cfcdab03c28493ddbe3146a43b44d5037d87ca0c870c2c0fabb60896dfb1298de927f195884f29edd914e3e2097071103
+    6979cd907d468b65143ea75140e38ebd;
+  bfb474fd71d891f24bb65d1563
+    259f9eb53b571ea629c54d57dd2d
+    42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040
+    a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c
+    559ea712ed9f509cf3ac9d44f1ac8cd0c6a11fd7e5250ce0de79f197f51f82903e8da278b4c5dbf8bcbebe7f52446cf523bee00462
+    f15cb4b18193f4922298801f9323a3c7;
+  037ba323fe1dc8151784873f
+    0eb5b647da6794c18b5337685a96
+    ""
+    ""
+    ""
+    b7dd404d4f1a01c8ef737b6c2525a3c1;
+  ed65b9aca338527ef19b09c0
+    63c46f88de9fd41e72d7b97e23e6
+    ea
+    ""
+    ""
+    ab6815775c61984db8e9f4927af022a0;
+  bdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012e4713df467
+    ""
+    95
+    7b
+    70aa0ae770a0161e22bc0ae606c70527;
+  630e7952d22bb02d7100b8b6
+    49377d20a8f083455b663e
+    ""
+    4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f
+    5ae21390a16833b1553ad00340cf88608eef0c77dec11bf992c8371c330f3c3b76484c95384949ec2cc42d1b943665f4
+    e0bd36e53a42d1c06bc4ef6ac241d106;
+  16e39815d4e9cfce3ed1ecdf
+    3d264a7f16cb16c2e815f422cd
+    f0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4f
+    cb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb
+    a5b3449e8af9f06e72f5f618131e205714de08712af78c71173e347e29259efd49ef786eebfb7fe5592e2838ca92f9f9
+    b6491d77b553f97cc3684ef4e7339515;
+  1c8dd0b00951f284649016ed
+    00456331854bc78bf43966eb0cfa
+    ""
+    9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f
+    0eb3df5285a44b93df6263d4a19c3468cc98d13cc57c92671fe450936feedb2d692d6e9b288ca7095ba3a16fc553d2b33f2e5e3285
+    ed1441556cce090353a8e651db8b7765;
+  30cbb7f0e4a973a8cd190107
+    314717a77456f3ff669c732b58db
+    8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0c
+    ae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a4
+    72c70c50bfc9891abb5d0f389a48e4ba925f1a5de1b522dfec32d0de805500ef56a0e3b248e52d50461e8673b51591d76aa7aac188
+    22315e09ed36b5e886972e3d97bb191f;
+  58cb948bdd409b68
+    7fa3a6827b480aa3a4c84cef64f6
+    ""
+    ""
+    ""
+    30c1077f4bdf19d1a75c2bdb0b791be0;
+  c9b53bf8f957f4b0
+    3cf43e89957f9a3e8128f8743d16
+    68
+    ""
+    ""
+    6f663abf27387105cc24b69ac2377f89;
+  7b7bb8deb9bd205b
+    70e04c091d205cdad9e9a79b1abf
+    ""
+    91
+    74
+    81956eab259749fa15c9a0c287a3c797;
+  b0851e5ca605ac84
+    51399587011677508a15dd
+    ""
+    e524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0
+    c229d22e2e97fdec03bf8725e466fe3130ef56c17c910ea6f6023fc4f389deb33eea058fd7878ee3f0947107da6ee92d
+    5bea96a8d2416fbb9f616e27b8d67b62;
+  ef5746ea8fdcccd2
+    13e33f7e8a5718fd25014107c8
+    e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70
+    d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8
+    67125d08b30abdf348054dd642f18f0802d58b7ad3f49abd77ee6e68146696f42a4a73993f0d3fd2754033dfafcf0b49
+    51db397a26bccb5dfb66aa47d15dc1ed;
+  ad68daac90cfe22d
+    2f1f2968cc42fa8b669ed3bb3542
+    ""
+    a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69
+    e20ad6334c2ecfaf8546c5917542e2b65b534724eefad63e1061805e673a6358d31753bdd4beb457112d41ccb39c306ae4aceb1fea
+    bb503bc1e42a7c837197827d4c4ba6ac;
+  d80ea12ff4bb5f06
+    9b8a2e86041c1b9fc214e9ca2186
+    ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089
+    d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4
+    13d0dff205001c5b6bf86c8810569bf634631c25dc146faf019d31b13437331abd317718f12e056d365c8d36520746656efd5fa8b1
+    a281566357e03991bc302355006a4df0;
+  fa8fec816ac861a8b33779f09e7a10fc02
+    a8f48afa3080ee119a52a9a817e4
+    ""
+    ""
+    ""
+    62e171992b3e9b84abd46d11865c70fd;
+  f2b94b0820cab383a8cffeea7c48631579
+    9dc875fba578c8ec4837898a9214
+    2b
+    ""
+    ""
+    c00cc0b5bacedb125f578b30d84d2198;
+  5b0677da1ac273117b45bcfff5d5f8b6fd
+    e2893232a9f81d14517ffae475f6
+    ""
+    b9
+    78
+    8a8a1da60db0bbd76cc5c4bcac79da2a;
+  4a43a67b3d380d2f9aaafe2dd721c0095c
+    8808847689211450ba8095
+    ""
+    ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feef
+    7a160e50b050bb3ca62c12501226cb0551b4dc3349721d71e08ccf2222dd831ac2a108691039f1ba41fc326d2a827bff
+    da9c04168e6dedb3579c2a9bd76f1692;
+  fdc2eb44dc8c0d5e8f444f7f4e0c893959
+    b74dc23a7bb40e7e0013e51506
+    86d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8
+    834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e73
+    7e0bd98a04cf07134ff5026bf10c6e2a4fcaead969223f4729ff57cc2d72f9c6976a03e4932fda63cacab98244f36385
+    34b97cb4b3ec851d86540afaefb7e6e5;
+  7882cd09c2b9a80f34c0fde11c2481b11f
+    c76bfa4dbf710a9e544e0c536ca1
+    ""
+    e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270
+    58c88119379227a3438f4be71c2b148eaae5dc87f047a10ac315de213b318eb0fd13be48c01b39654ec0521caa1da513b9fc1b9947
+    1176c87b5d31fb87b7454e7aff5104ba;
+  295dfc0ca6551ca4bdb75359f91cb9d921
+    056b7de74fc9a9b37154ce6c0b39
+    6179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fa
+    c7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b5
+    d5559d4ffc3be85cfdb261126b89cb7e7fae82a3f954bf79ffe6f7603ee58b5d2d37747ecfa24ad41bdaa0b1fd7c82e0e04e81c69f
+    507ed27681b30a6cdaab64aba8bb3ac1;
+}
+
+serpent-ocb3-mct {
+  16 36d3bf694fedee5e20e35745d9f647e9;
+  24 924c5b38d6df87dab11042e56bb0434e;
+  32 5b8e3684bde5c8b28bb87796aaf95b17;
+  16 506bd45f5b6eb67ceeb408b9;
+  24 650f258975a5d1f6596ff2af;
+  32 fd5488e927ecafd96722e92b;
+  16 5294561007b55710;
+  24 d3a5062ec84f5ac8;
+  32 2b883de71615444d;
+}
+
+serpent-ocb3-mct {
+  32 5b8e3684bde5c8b28bb87796aaf95b17;
+  28 1a93fd62a9e9a3cef4407833bcaba842;
+  24 924c5b38d6df87dab11042e56bb0434e;
+  20 626a7bdd05dfbed8287c7a7cec11b863;
+  16 36d3bf694fedee5e20e35745d9f647e9;
+  12 5a6486f6ba3b10d486c628147c71a85c;
+  10 0664a0cdd817da522ce92837ec06ebc0;
+   8 aa155e08b41857c4abe54180e6c50bbb;
+   4 328cd59c0a989fb70c0339066da49aa7;
+  32 fd5488e927ecafd96722e92b;
+  28 f080658ee65dfd9d54e19ae5;
+  24 650f258975a5d1f6596ff2af;
+  20 d141c903a4d29332b36b2984;
+  16 506bd45f5b6eb67ceeb408b9;
+  12 3c53bf904f4edbb691e7af8e;
+  10 849f7d73dd7e48655f062340;
+   8 048b157a38f4281968f840e7;
+   4 f52c2156342549de8bf99f08;
+  32 2b883de71615444d;
+  28 d9776aee81a378ea;
+  24 d3a5062ec84f5ac8;
+  20 e1e805b319485007;
+  16 5294561007b55710;
+  12 00edada26968f413;
+  10 dff51ca249d51583;
+   8 87ec3336240f6f98;
+   4 305dce068342b3ca;
+}
index 63ac0cb..2af56e9 100644 (file)
@@ -99,3 +99,246 @@ skipjack {
   06e3c0e541f4aae6fe93 40009f8a465a9feb 0e7aace421bc79d8;
   2ea09f1cc89e064f09bc 543208b05bfa3858 a95d87fad12c3593;
 }
+
+skipjack-cmac {
+  e4bef260d7bcda163547
+    ""
+    5a0fba9745b5a83e;
+  d348b7551195e7702290
+    7d
+    8610508eeee08d29;
+  d1dff7dac5c9941d26d0
+    c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689d
+    46b1504483d84dff;
+  aaa9060d2d4b60030623
+    65b0a54364c76c160f11896c4794846ecfa14a
+    cffcc55881902725;
+}
+
+skipjack-ccm {
+  e4bef260d7bcda163547
+    d348b7
+    ""
+    ""
+    ""
+    a8e3e588;
+  551195e77022907dd1df
+    f7dac5
+    c9
+    ""
+    ""
+    3b47dc26;
+  941d26d0c6eb14ad568f
+    86edd1
+    ""
+    dc
+    fe
+    61bfe011;
+  9268eeee533285a6ed81
+    0c9b689daa
+    a9060d2d4b6003062365b0a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff77bf79192a
+    3599e35441a20dab5e973151a0f3d8dbde983d9a896d3463
+    dee97ef167dde431;
+  5b50ade5d9cd739a3d1f
+    337f29549e
+    6b0d27a4ba234085406a6136512061f7080cc0
+    7df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029
+    a72ba97fe436bdad5e7416aa41b733be94324faf2d70cc67a31559f7d7
+    d14f0eba040f800d;
+}
+
+skipjack-eax {
+  e4bef260d7bcda163547
+    ""
+    ""
+    ""
+    ""
+    b15f1791e4065ebd;
+  d348b7551195e7702290
+    7d
+    ""
+    ""
+    ""
+    58aed98d9796d86e;
+  d1dff7dac5c9941d26d0
+    ""
+    c6
+    ""
+    ""
+    ed16d102bdd549c9;
+  eb14ad568f86edd1dc92
+    ""
+    ""
+    68
+    1c
+    c1a5644ab08ad1dc;
+  eeee533285a6ed810c9b
+    689daaa9060d2d4b
+    6003062365b0a54364c76c160f11896c4794846ecfa14a71
+    30c9f137120634c9519848a877ff77bf79192a5b50ade5d9
+    b4bb56af916bc1a14e6a106346b9fbc1989b20d12275469f
+    06a4958aa50a4260;
+  cd739a3d1f337f29549e
+    6b0d27a4ba2340
+    85406a6136512061f7080cc07df0591d8fa21f
+    2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc876
+    1e9afd31797d761c4f9ffbf0031a227872fa8b21de658b8fdb22514c48
+    44adbb6a2eae0a93;
+}
+
+skipjack-gcm {
+  e4bef260d7bcda163547
+    ""
+    ""
+    ""
+    ""
+    6fa498e64c57905e;
+  d348b7551195e7702290
+    7d
+    ""
+    ""
+    ""
+    cc2fd0c06756c545;
+  d1dff7dac5c9941d26d0
+    ""
+    c6
+    ""
+    ""
+    d6c1997db60c0a1c;
+  eb14ad568f86edd1dc92
+    ""
+    ""
+    68
+    98
+    08825f061a3ea120;
+  eeee533285a6ed810c9b
+    689daaa9060d2d4b
+    6003062365b0a54364c76c160f11896c4794846ecfa14a71
+    30c9f137120634c9519848a877ff77bf79192a5b50ade5d9
+    0a048d8b451ed2cd53dc70a177834525881e84046c4dd904
+    222801fac5bfd46c;
+  cd739a3d1f337f29549e
+    6b0d27a4
+    ba234085406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029
+    f3bf97b9c9c15761437a42c826abadf01e9207fd4b172e200a6d7aea3a77c85c3a
+    fff6db552209b7b8;
+  df3e6057acc87638f508
+    046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dcea
+    a7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    b96e1e6d2db5000c5bbbd06e86ab26c3a2a060b3eeeb1899793a743bc9
+    74694b07f5866d80;
+}
+
+skipjack-ocb1 {
+  e4bef260d7bcda163547
+    d348b7551195e770
+    ""
+    ""
+    ""
+    28afba7b57208bb2;
+  22907dd1dff7dac5c994
+    1d26d0c6eb14ad56
+    8f
+    ""
+    ""
+    62f000b7bdb0d1dc;
+  86edd1dc9268eeee5332
+    85a6ed810c9b689d
+    ""
+    aa
+    84
+    c92bec4a841eab50;
+  a9060d2d4b6003062365
+    b0a54364c76c160f
+    ""
+    11896c4794846ecfa14a7130c9f137120634c9519848a877
+    50d328a84a166d75e1574aafc3a6847451f766a4e5b1d506
+    c155363b2c86bd70;
+  ff77bf79192a5b50ade5
+    d9cd739a3d1f337f
+    29549e6b0d27a4ba234085406a6136512061f7080cc07df0
+    591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9
+    b9f8bca7a0f1024a232217f4d9acd0187997bdb2348287f9
+    d8d3f45231b59769;
+  269029df3e6057acc876
+    38f508046733d9ff
+    ""
+    61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c3
+    3b5a6606907f297d26827ab95798171debff551df36e0ae8f6f29026f8
+    24734c1d6c3da996;
+  8201a894476b3f102b75
+    2eb9529533966f27
+    043eb621b7f65b000961040ef2f9b2fc5fa450
+    727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a
+    694a1412b0ab1b6fb698a9eb920fd2910c7625b68558fbe9ffda426f55
+    19c658ead145b558;
+}
+
+skipjack-pmac1 {
+  e4bef260d7bcda163547
+    ""
+    b663da5674ffc5d1;
+  d348b7551195e7702290
+    7d
+    554a2fb9de2d30ae;
+  d1dff7dac5c9941d26d0
+    c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689d
+    0318df96a103a2f1;
+  aaa9060d2d4b60030623
+    65b0a54364c76c160f11896c4794846ecfa14a
+    b3a737b39bf1c95d;
+}
+
+skipjack-ocb3 {
+  e4bef260d7bcda163547
+    d348b7551195
+    ""
+    ""
+    ""
+    306c2123c229d86a;
+  e77022907dd1dff7dac5
+    c9941d26d0c6
+    eb
+    ""
+    ""
+    a0f5e0a9d6193d8e;
+  14ad568f86edd1dc9268
+    eeee533285a6
+    ""
+    ed
+    76
+    b1f29902bbde9441;
+  810c9b689daaa9060d2d
+    4b6003
+    ""
+    062365b0a54364c76c160f11896c4794846ecfa14a7130c9
+    62299168f2ce7ea1488f71fbde61613002efcc4815d4674b
+    f9d14a84093df62a;
+  f137120634c9519848a8
+    77ff77bf79
+    192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba2340
+    85406a6136512061f7080cc07df0591d8fa21f2dd88374d8
+    7ee7aa9e2d4e7e5f4b9c9e254ffd3868f8ce577bc82b0239
+    0560b1fcaba5682f;
+  cde8e160ad10997a2163
+    5c6d62c92690
+    ""
+    29df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    914f81636ba12b551c60b41dcf566e447d02d15d2113c09678b1fca4ae
+    b7161acf1efb88ec;
+  05e505da1435dceaa7b1
+    cc49ae1d50c3
+    8201a894476b3f102b752eb9529533966f2704
+    3eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d
+    78498440ea075861116531b9ad62fa7d399948260edc0bdd04e04a4327
+    39de18c8572cfd02;
+}
+
+skipjack-ocb3-mct {
+  10 63be3f7aef5a5f98;
+  10 dbe0b1ff8673;
+  10 b26e14c0;
+}
index 7b348e2..9d0cbf9 100644 (file)
@@ -521,3 +521,687 @@ square {
   00000000000000000000000000000001
        0f1e2d3c4b5a69788796a5b4c3d2e1f0 69bd984641e0aa887bc23738f60070db;
 }
+
+square-cmac {
+  f260d7bc
+    ""
+    29984a33657f622352c1ee581eab804e;
+  da163547
+    d3
+    cdc5e3485007695cdeb53ce1e8cec39e;
+  48b75511
+    95e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003
+    7fdd1689e5a004d05b0bc92e3ecc8f16;
+  062365b0
+    a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd
+    95f37b226b5f157fb68c9b235085799a;
+  739a3d1f337f29549e6b0d27
+    ""
+    c48de9e2768ea55c731b65c22052aebd;
+  a4ba234085406a6136512061
+    f7
+    4710b0fec299631f0d53e9ce3b0a172b;
+  080cc07df0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    88eeeecc2b156790ac07c7c4c7b6c431;
+  05e505da1435dceaa7b1cc49
+    ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a
+    ac18ee08b5e9a21581b33f73b63e9a41;
+  9b542cde52ebfda1
+    ""
+    d45f57812f3249ba56239bf41459682c;
+  9d0ccc520f215eb5
+    7b
+    12f4a147fd87d19814850cea849fab85;
+  b3a4f3ebbbb18ac6
+    c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b
+    950e0997bc4188db73c08df2e1e880a6;
+  69ac26afa3349829
+    b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d156325
+    a1fa99cf13347b5b803ccc6c2e183381;
+}
+
+square-ccm {
+  f260d7bc
+    da163547d348b7551195e7
+    ""
+    ""
+    ""
+    6f6ddeb0;
+  7022907d
+    d1dff7dac5c9941d26d0c6
+    eb
+    ""
+    ""
+    bba9ea11;
+  14ad568f
+    86edd1dc9268eeee533285
+    ""
+    a6
+    0a
+    507bd8ea;
+  ed810c9b
+    689daaa9060d2d4b60
+    03062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd
+    739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    2de5299d997f5a95d32115f84b8cbc072043580e27bb6ace6654173512e0d464ce4358899c43ac2befe5cbe68155797b
+    217a8c66edf6aad2f17f555c8936028b;
+  21635c6d
+    62c9269029df3e6057
+    acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a8
+    94476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57b
+    f88c7d34053cc7278c3e3b09715ab3dec3aa050aa70aa6dcd560a9ea58ddd10857b9bcffb98e2af8a3c851f60f540ab8872af0df1d
+    a65b843ead57238ecd6bf0eea46d6fbe;
+  b3a4f3ebbbb18ac6c95a97a4
+    8030370c33d090c54215ab
+    ""
+    ""
+    ""
+    345fc32c;
+  d6b3ad54efc9a38378c5b93b
+    f4f2aad2605faee2b03fb6
+    48
+    ""
+    ""
+    89dc30e5;
+  e27fff63102758fe2b69ac26
+    afa3349829b94586306fed
+    ""
+    54
+    ba
+    595a1d50;
+  154f8f28523c03d4de160015
+    7846b710ee72807a22
+    19bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b
+    0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a
+    562758f6a2b849784695d8f36b992eb75a439f9e4daaffff462c1c0e2ed738ae81857040c7bc33093d5d962635b162b3
+    de5af35682b227c7c585fd7ac841b903;
+  42bb8fdb233bfa6a5cfb0bad
+    7d95214ade49cb3b6f
+    5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b
+    09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d71
+    ef06fd51aee9d8dc17ae50cb1aede6b88f5a5f0e2bfa12f825ef09a757e06a1fd2571bc34e3d6796ea05613d6323cf0ea90dfe15c8
+    efd15ead8ef69008007fb696c5e0de7b;
+  00b8b649377d20a8
+    f083455b663e4ee1315f3c
+    ""
+    ""
+    ""
+    6f0d9e5d;
+  8f2aebfa921451dc
+    d1af5813b70d30ce2f1fef
+    6e
+    ""
+    ""
+    76d11bad;
+  f315d0798391805d
+    a08da3aefc5f8584b7c5e6
+    ""
+    17
+    0f
+    8aa0fb43;
+  669c0f16e39815d4
+    e9cfce3ed1ecdf3d26
+    4a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986
+    981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511
+    b98ec80c9bfcbbf817b03abb770cb6121b7dbf4b497b1af44e9c910bfa324279416423f51b97738f01f27c70436330ef
+    4d5d0ebb6586b5e8405e66fed4c0361e;
+  265febd11c164720
+    eef9eb1c8dd0b00951
+    f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc28
+    10d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c73
+    e948dd0b7f57ae2f94ed538207db42a1f4e3e743aa1105e600284b3b92ce82b4c99ee0a2db8f7f51d17a7084aa068eba1a1f0cd0a7
+    401f2e64af6c6d18382d1546abe984e4;
+}
+
+square-eax {
+  f260d7bc
+    ""
+    ""
+    ""
+    ""
+    66848361a1d85500e3efc4889f3c2bd1;
+  da163547
+    d3
+    ""
+    ""
+    ""
+    3e14f9c0f9b208db9a52730d00525dc6;
+  48b75511
+    ""
+    95
+    ""
+    ""
+    1b81e7698ff5e258ea2e8f75b7bcfd88;
+  e7702290
+    ""
+    ""
+    7d
+    d5
+    c256dd01d1ee4db1387ef0f0b3d43b57;
+  d1dff7da
+    c5c9941d26d0c6eb14ad568f86edd1dc
+    9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137
+    120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080c
+    cd9fbedf0befc513ec208493902b99f4e304654e0460d29920804d69dc150fa3e31d86a755ba930d0211fee9b7ca5f9f
+    f01b0b0089bf48fedc2c21556a1b644a;
+  c07df059
+    1d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da
+    1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b54
+    b88f48021b69e18d9457120fc11ebdd467c0b1119b5ab0bd16a5c3aa70e263d3ab841cbe6bba4fd02c94690dd143746294f825c26f
+    e0efd3bd220277de49de30272939c21c;
+  2cde52ebfda19d0ccc520f21
+    ""
+    ""
+    ""
+    ""
+    8eac437bb3e523a1588a11e05db64b05;
+  5eb57bb3a4f3ebbbb18ac6c9
+    5a
+    ""
+    ""
+    ""
+    8950206e80699724eecfcaa54766d533;
+  97a48030370c33d090c54215
+    ""
+    ab
+    ""
+    ""
+    ddde409a326fe6d98ce631e1da7f54eb;
+  d6b3ad54efc9a38378c5b93b
+    ""
+    ""
+    f4
+    d8
+    8288b113a8d26d40aba09cb3f2195dd8;
+  f2aad2605faee2b03fb648e2
+    7fff63102758fe2b69ac26afa3349829
+    b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b57
+    1ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f7682
+    4d1e0a695a91107ecb1d5247d28cfbf19237fc3f63e45f068d11dcbda21d83edcba5bdf9d3f06c2c8cab82fc41bf95dc
+    530d31b751cdf63e4d3f69dbd3623c8a;
+  81e040a9b9a222bd689aef66
+    f5306ceb0c6b08ac8b0a22260c571b
+    4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5
+    b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1d
+    d547e342eb52d40545b00733505c306065b84193dc67ad9436f2acff5224cfe199885811c635803ec7d36a4756a55f97a7d79de113
+    bed4ee2118bb4c7b7a12e34c60b7db7a;
+  ad89d4b9b12012e4
+    ""
+    ""
+    ""
+    ""
+    c2044f9358ab48997b37cd48c3d71ff0;
+  713df46795630e79
+    52
+    ""
+    ""
+    ""
+    7170fe71433b54c9891444470353f8ee;
+  d22bb02d7100b8b6
+    ""
+    49
+    ""
+    ""
+    070caac7af2fafb9acbc0dc299952b52;
+  377d20a8f083455b
+    ""
+    ""
+    66
+    91
+    1871fba93a1bd987dd232ffd84222d45;
+  3e4ee1315f3c8f2a
+    ebfa921451dcd1af5813b70d30ce2f1f
+    ef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f4
+    22cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8
+    34bea45625f646aa4fea5c08966df347998c5e91c3e243ddbae6ec95cbd9aef41e52e5bb71cc8d38470075e5f342d0a5
+    b7d0633c6ed773da8c265c633cf8ebcb;
+  bc4fcb70e27e98ef
+    1f0446b42fb144d44b6d00f06dc188
+    d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331
+    854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5f
+    b11e564fe1caa81babd189007d9fdf983b4a086302d1eb98daec4f6c91849f873b84982b0a5c037b952355e0a0c916a3967e7ddb69
+    b87b90233e12e003b8ffc0fa198d2269;
+}
+
+square-gcm {
+  f260d7bc
+    ""
+    ""
+    ""
+    ""
+    66ac17c939ebd05ca617e77ba83201e9;
+  da163547
+    d3
+    ""
+    ""
+    ""
+    8361e8e723233ce477ef9132624bfb9e;
+  48b75511
+    ""
+    95
+    ""
+    ""
+    29a7e874d6054c42dcc1ada2e6f38cf8;
+  e7702290
+    ""
+    ""
+    7d
+    7d
+    d439d2be5e01a0d767739abd80dbc293;
+  d1dff7da
+    c5c9941d26d0c6eb14ad568f86edd1dc
+    9268eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f137
+    120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080c
+    f36d7d44b8637a2a560a8e89a7a5a5c754de68194a47bb2befdf2384e91eb38cc70807a42a687eb3113c9c223e1c8763
+    e13b8f67d62247d887180b4cfb90eb6b;
+  c07df059
+    1d8fa21f2dd88374d8cde8e1
+    60ad10997a21635c6d62c9269029df3e6057ac
+    c87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27
+    863f1602c0fb45b1a3264e8140b5addd0a82feb9b5e632fc539b3ed83667eecbf32c65dcacec865ea475c3506d61d00db1ba24288ba1a13ef1
+    58de876618ed18d0aab09ef9acd06bae;
+  043eb621
+    b7f65b000961040ef2f9b2fc5fa450
+    727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6
+    b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c
+    1e559d1bc26402ae885ebcb0946a573d44df5d59476510247197bc816467f5386887c5543f3a2256e26f44a91b31afcb7bcc85b2dc
+    83783d53918eff6b310540ac8c1c5d85;
+  03d4de1600157846b710ee72
+    ""
+    ""
+    ""
+    ""
+    ddd01942ddf92df99dcada451c651de0;
+  807a2219bfb474fd71d891f2
+    4b
+    ""
+    ""
+    ""
+    85e41566cb1b62bbe5c3e3a2a5f35779;
+  b65d1563259f9eb53b571ea6
+    ""
+    29
+    ""
+    ""
+    212a5e2129cd24e177c03718181637d0;
+  c54d57dd2d42f70800df9fcb
+    ""
+    ""
+    ac
+    28
+    1b1cb85207cef5e0fe224f9b1d77f836;
+  a48b77dba189196d1ebba10b
+    0467cb9fc2712a199e533fa9156308cd
+    ec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214a
+    de49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b
+    2e5f808b009e36fb4f2cf59ec0cdd6f7aac023b9e6037528879a3389aca459a56a337073116aadb30f44453a3bd540df
+    637a59d017456d0fffea63306283df28;
+  09c063c46f88de9fd41e72d7
+    b97e23e6eabdff3bcd211499
+    268878dbf30f1dad89d4b9b12012e4713df467
+    95630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805d
+    f37ebcd6beca3d239c15bc8e98b774a0c527c87c6fa04ebed3098db72f36ddccba0ee84417d99156b229b6a9b3d6b0d4139233e7d6793618a7
+    a21999c562eaf6d513e48d6a0e12d77c;
+  a08da3aefc5f8584b7c5e617
+    669c0f16e39815d4e9cfce3ed1ecdf
+    3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd
+    52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae98
+    5e606cf43bfe84c8a64a2ab5d04d377da99053d2dd80b4b9e3b161a04b58b96bc7b750b95fdb479d36cebaebb300526d6d3c8a97e1
+    7d73467c21c6b79fd07b6670875687f9;
+  5511265febd11c16
+    ""
+    ""
+    ""
+    ""
+    d06bc05e975b21905cefbf33aed2558b;
+  4720eef9eb1c8dd0
+    b0
+    ""
+    ""
+    ""
+    6088d2aa7493efa2bb71465f9b4a4a7f;
+  0951f284649016ed
+    ""
+    00
+    ""
+    ""
+    bfc486eed4840dddb9b8eb5cdc0895bb;
+  456331854bc78bf4
+    ""
+    ""
+    39
+    22
+    a44fd42c2bed09a530a167ff512d53c0;
+  66eb0cfa9138ddc3
+    9908445608fe95e81c2533e31c9c1a98
+    51bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717
+    a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945f
+    e7ef1f4b63cb4ab8b7ee9c733450f6bf4f921ca5fef77eaebb8cf2fd614e0de3f87e22a59b20f4f7af7af8f9c2175924
+    1b90917328ea382e254f6d0aa8d8fb50;
+  fd505003cc0cae9c
+    e021a5f1fa4ffa91544485f1
+    a1258b2b9b8f0911e32d65cc1770a18cbfe6ef
+    fd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a
+    90f4bb5b8e60ae32eb97f506c90a0e71156ec2e4a39c1ae669502bbbd6724a3f5713dcdcdacb374f31723a9003a8402dda6b0260362527a72f
+    2256d08180ac3ed3ab48daa0b86d4cc0;
+  3e8128f8743d1668
+    7b7bb8deb9bd205b70e04c091d205c
+    dad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d
+    65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8
+    58a997404e629f9e9d5652bd076188c9bd4a631d3e2486a944151f3cf29edbfc62e3910c0b341052b475d623f2339488c9983e0990
+    1762e398f8582d72954ed718af4f677a;
+}
+
+square-ocb1 {
+  f260d7bc
+    da163547d348b7551195e77022907dd1
+    ""
+    ""
+    ""
+    4ec5c312526c730e41458aca324ae0a0;
+  dff7dac5
+    c9941d26d0c6eb14ad568f86edd1dc92
+    68
+    ""
+    ""
+    d0cc24f9084261cdaf4393e7b250701b;
+  eeee5332
+    85a6ed810c9b689daaa9060d2d4b6003
+    ""
+    06
+    72
+    1e1671f47f5bd8b32ebb09c019105281;
+  2365b0a5
+    4364c76c160f11896c4794846ecfa14a
+    ""
+    7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a613651
+    11e134a63441fc0951b37098764822d6eaa47187fe96a2f3658563cc612c857f0dd5d4e056c820a3670828dd7f5a9d1c
+    86893621402b0a64fded1b34d47504fb;
+  2061f708
+    0cc07df0591d8fa21f2dd88374d8cde8
+    e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd4705e505da14
+    35dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450
+    1599b31480519c999bbc9fd4fb1a24676071040c16ff4a6834cdaf46c51ccbb9522cfde0e2df2867871cabd4aa73c33a
+    e8e411a4ac803610a4f2a8e1b6aabba9;
+  727a9b54
+    2cde52ebfda19d0ccc520f215eb57bb3
+    ""
+    a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758
+    384781d5a43f9e0d692787efd9cbbff3f8cc6e154544695653e495e63b3da9730b781b214f5c8f6d940542c76c24f0acacfcf099c0
+    5fa2cade7fa22e8df91b9f91593f9d3a;
+  fe2b69ac
+    26afa3349829b94586306fed54154f8f
+    28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d
+    57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689a
+    4c8c3874f73c8504b64bbe612589c103a462720d244c3092221b6c7b31a162aebefaea934d2ac8eb9e03f8f480aa1407d58a8a8e0f
+    03fa1ede942984e0ae4f30946f7e0201;
+  ef66f5306ceb0c6b08ac8b0a
+    22260c571b4a42bb8fdb233bfa6a5cfb
+    ""
+    ""
+    ""
+    ae26bcd1fc7065f659ec2e37cdbb4d06;
+  0bad7d95214ade49cb3b6f5f
+    e8368131115c037ba323fe1dc8151784
+    87
+    ""
+    ""
+    9f5a8cdf70fc430a52be4efbe40903b5;
+  3f0eb5b647da6794c18b5337
+    685a96ed65b9aca338527ef19b09c063
+    ""
+    c4
+    b1
+    5358be539c81b8af364ee06a6d510baf;
+  6f88de9fd41e72d7b97e23e6
+    eabdff3bcd211499268878dbf30f1dad
+    ""
+    89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dc
+    6a33c5e3320001aceef2ddb9eb101bc7a44cbbbe05a3a4fffe25cc658d1a5834701a2fd135d964d2aafa112d45c44727
+    a1b70c95ccff432cd7ffac9fcfc36d4b;
+  d1af5813b70d30ce2f1fef6e
+    f315d0798391805da08da3aefc5f8584
+    b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb6
+    58b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d
+    92a2d4564bf2ce07ddfc07a4c61b642f82e07603156c3e67a21fc29958ae1ab0f11689b5361185a5e36e11f8764939c2
+    f4f96b643edc928c53440ca84037253d;
+  00f06dc188d472a784e0c6f2
+    1195a3b9f4ae985511265febd11c1647
+    ""
+    20eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc28
+    6850774629192af796f0a661a429cfd5a235499b4f839206ab9a23dbeed0566217317c51538556edf394c8d83dffedfa381222d7f6
+    bf6ea195e668f32372ecce468c963344;
+  10d858cbbc8424d126b807e6
+    daa089c3f9099c5ffb824173d7634c04
+    226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b73037
+    4ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65
+    5016f4b0746fe26e4c8ff63a0fb3a3af5070ba789900e4b69b90c42331d2bef65a6d520ed660c6b8b21180a3e0706e57b6f8e99680
+    5336c139328f5e30663524991bca106e;
+  cc1770a18cbfe6ef
+    fd1ff6778554acf1270485b203a3c1c4
+    ""
+    ""
+    ""
+    68289e95ba9adc986ec25334e9821681;
+  c967c0a458cb948b
+    dd409b687fa3a6827b480aa3a4c84cef
+    64
+    ""
+    ""
+    c3fd1e84842901c9030c844f1cf2a037;
+  f6c9b53bf8f957f4
+    b03cf43e89957f9a3e8128f8743d1668
+    ""
+    7b
+    4d
+    65211e0de7d279e5ecde8793097d5217;
+  7bb8deb9bd205b70
+    e04c091d205cdad9e9a79b1abf91b085
+    ""
+    1e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7ef
+    8cdbd696f4e8b357c8077fd749e4bb0a0f24c8b95deebd0174708f13d6656315c47a9fe9cf561d4afb4e48ab68249248
+    ba46b27e9799540b1f2fed90f8404169;
+  edef3401539c51d2
+    a90bbf7f1bfc338ab0ef5746ea8fdccc
+    d213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5
+    afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2da
+    f227e7487fe14220150b10fa5456bf655b53c2b3cd2200ee882b912d9ad71146f8a937eae0ac4fbdcc99602783caf769
+    0d78408bce85318de6bcfd8cdc7579ff;
+  c07ecde95759ac46
+    fee6dda7abc8ad68daac90cfe22d2f1f
+    ""
+    2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d9683
+    88e08b26d8c6c245d09dedb7a2b2482f0a5816940b89e87ed5c3a0ca573d2b8be39e18d252d84b4d9aad35fc54dbc57306c45676c9
+    2d9921c55910b5fd930615d61dde717a;
+  6c5f87b95460938d
+    e1288c69d80ea12ff4bb5f069b8a2e86
+    041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076
+    817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e
+    a450198ec39d53163f8db0c90b59a3b5d02dd4ae0c5c800e9b30bb747082e383ffaf85cae517a18ce337b064f74286cf8d843e0696
+    5a40990ae1dfae2c5cd30d9b32c794c5;
+}
+
+square-pmac1 {
+  f260d7bc
+    ""
+    aec43cacfa9e76ed9f6c0176974d1111;
+  da163547
+    d3
+    38e2ce3d69f8fb21ed28599d77607fe8;
+  48b75511
+    95e77022907dd1dff7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee533285a6ed810c9b689daaa9060d2d4b6003
+    7c8785ab3dcb7d71ba3d6fcf7ba32376;
+  062365b0
+    a54364c76c160f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd
+    b21eb39143554c29a104eb7ca8d10ca8;
+  739a3d1f337f29549e6b0d27
+    ""
+    8a5016e4834fa9fe8ef64746a89189ce;
+  a4ba234085406a6136512061
+    f7
+    21e70bad22188fa3845c86a33d466528;
+  080cc07df0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    fdb16c9e5914268aa7dca6ee20efb72e;
+  05e505da1435dceaa7b1cc49
+    ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a
+    c69607969a66a1f0e09c40a8b8e7b303;
+  9b542cde52ebfda1
+    ""
+    718839aeaf776c252d578376fe739e46;
+  9d0ccc520f215eb5
+    7b
+    4830cb31ec114ff8704f183f95d06200;
+  b3a4f3ebbbb18ac6
+    c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb648e27fff63102758fe2b
+    c5aa56a0bf29d192de4e3db9174b1b9a;
+  69ac26afa3349829
+    b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d156325
+    e6d24bd14f25e2fe8909354cdac337f5;
+}
+
+square-ocb3 {
+  f260d7bc
+    da163547d348b7551195e7702290
+    ""
+    ""
+    ""
+    b1669cbf9b59f73b4288eb0761332190;
+  7dd1dff7
+    dac5c9941d26d0c6eb14ad568f86
+    ed
+    ""
+    ""
+    780716f09513ecb8dd6f322f3901fd27;
+  d1dc9268
+    eeee533285a6ed810c9b689daaa9
+    ""
+    06
+    b8
+    1fcf843450fa4d3da50d8de6525119eb;
+  0d2d4b60
+    03062365b0a54364c76c16
+    ""
+    0f11896c4794846ecfa14a7130c9f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d
+    33f91dd536f3667b220ac4fa9ef6bec830fc052968f5c3c78141ad56254dbe7fff02e85ea5a278bce0c9a5037caa31f0
+    11621f557ad6c52a82e8d9495bb284e2;
+  27a4ba23
+    4085406a6136512061f7080cc0
+    7df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3
+    b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7
+    1859d78e9ad0fbc8bf76a97f08e6de088994238974dce458f7dc145948b8ba9f8b8f52c82a1ff60046350eeec8936379
+    350f84d218392b1282daa7db5ebc4e5e;
+  f65b0009
+    61040ef2f9b2fc5fa450727a9b54
+    ""
+    2cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aa
+    664cabfb69a25342a0bcc17049c316c78c412df3efbf75cc192b936dccf87b3c094d51468c20911a477cd6a214c403ff99abec313a
+    09b989eae5e6973b675f06ab4b9ad1e7;
+  d2605fae
+    e2b03fb648e27fff63102758fe2b
+    69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d8
+    91f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9
+    9f53984003391daa1fe81c1e9385d1d902f330b930b225a8164f06adeaff820d08dfceeba9ae1a9639d556bba8ad6563186d022240
+    64d960c38db07c9ede67bd56b122544e;
+  156308cdec3f768281e040a9
+    b9a222bd689aef66f5306ceb0c6b
+    ""
+    ""
+    ""
+    c09ceb18e7c3a8ac514ff85bca3ff3c5;
+  08ac8b0a22260c571b4a42bb
+    8fdb233bfa6a5cfb0bad7d95214a
+    de
+    ""
+    ""
+    80ad7d8b14ff64d06b79cd39c7440775;
+  49cb3b6f5fe8368131115c03
+    7ba323fe1dc8151784873f0eb5b6
+    ""
+    47
+    74
+    6e58478155a6c0007a0323c4235d8e70;
+  da6794c18b5337685a96ed65
+    b9aca338527ef19b09c063
+    ""
+    c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb0
+    867bb322577ed2e766f857c22e0114e95c6ffa900fb90bc3937effe8dfa93140d9a58ba0827e5b06c1304ef17fae2c33
+    0e880f9fe586b0761eb98b29b1636b65;
+  2d7100b8b649377d20a8f083
+    455b663e4ee1315f3c8f2aebfa
+    921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3e
+    d1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd5214
+    738258f0995345cfb20acfae2607aeb91871d5a7b704a82e866350f8e3a28dadef97edc6b7618a12967000642abd3cbe
+    6a41eed95fa7c3c529eee84ea0a4770a;
+  7ed12ca986981a874498ad0a
+    bef8bc4fcb70e27e98ef1f0446b4
+    ""
+    2fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed004563
+    fe2c297cdc8e4761c2d70f8ac5c8431bbdc7560712b651f182aa471c5fa6d9569d0f890c8ab2a5dc6e6e61a130a20d533dc013b6e7
+    1722ffbd31d1def40cc073828ccc4cfb;
+  31854bc78bf43966eb0cfa91
+    38ddc39908445608fe95e81c2533
+    e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4
+    a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6
+    e55a772b18315f4096513d5bf39f4c42665be5375ccee48d7f7c9bb8ad05644e2a2d92b485a2c42514e2abb4940045ed05b2d15bfa
+    01a830efc22048f44dc01e1db446b5bb;
+  a9f2c0945ffd5050
+    03cc0cae9ce021a5f1fa4ffa9154
+    ""
+    ""
+    ""
+    75029ca958d142837b6cd9138b81c0cf;
+  4485f1a1258b2b9b
+    8f0911e32d65cc1770a18cbfe6ef
+    fd
+    ""
+    ""
+    8568e94583082cdd23e3f72b9f28d106;
+  1ff6778554acf127
+    0485b203a3c1c4c967c0a458cb94
+    ""
+    8b
+    4e
+    10be6791bce4cff5866df5348e7e9ef3;
+  dd409b687fa3a682
+    7b480aa3a4c84cef64f6c9
+    ""
+    b53bf8f957f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e
+    4511dc2330fa5033e1ac63dd1901ed10c5c919a6eed4e953cef5b7847f86f6db03d68301a6dea2c4f8ff6173da5800a7
+    8bd0072dd3ca8de80eddb1cfca3680fd;
+  5ca605ac84513995
+    87011677508a15dde524af3e2b
+    ee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8f
+    dcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc
+    2212a8678c5de88205f0fea2785f6dbe17d974ff4d64a533c573ca6d9a8079a55bd3241f6783705d81498a2426d522d3
+    0e895642d052f0695d3ade0d052738cd;
+  5ba5afabf8c3122d
+    12d7ff3c41122d70d17d4569eaff
+    ""
+    59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f29
+    b5e9c68bbf184cfaece73aa7d566a115709a25c94217851433e62f2a28aa9d45a084f521fc5514af2f66c573ce79d817d74a6480b9
+    613c417ce774d4a717ea6a5fd0ee5b06;
+  68cc42fa8b669ed3
+    bb3542a9cf44bbc8c6254d980398
+    bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69d8
+    0ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba600
+    08a8bccee9fb6b7449fdbd1dfcb6836385770d4f6592e27c563250f869ad4262a87159fc9a0d42b61e1f59acfa244c7bdee8cd03ef
+    f5cf62fa77aba0b2285dc3d231ae2cd5;
+}
+
+square-ocb3-mct {
+  16 47b0a29f45c1b000f1a0c27eee7f42e7;
+  12 7a80e7d6e556778f77a327928ff4dc35;
+   8 886bfcb71cd24995911ed011b231d99e;
+   4 d0b2597b73f284932af5a5db0fd1fb3d;
+  16 5c3d0dfbee0d8977a7cee660;
+  12 6057212ee2684bb36520d44b;
+   8 5f0f721b8171461d242bb883;
+   4 127b569653ace9af8aac7f47;
+  16 4184125b37fbd3fc;
+  12 258e75d36b5359b3;
+   8 bd8c4a18f64be7cf;
+   4 55a5c5e40c4de0e9;
+}
index 9eec55d..e76f9ef 100644 (file)
@@ -72,3 +72,912 @@ tea {
   c86c21d8c26dc291f662c8f2fe79b74b 0993d3b68c1d4a5d d33c2e41dd5da131;
   af4f4615c7c298639b9728251991419f 1e268f9e710313b5 a9478f8cf88b7e10;
 }
+
+tea-cmac {
+  60d7bcda163547d348b7551195
+    ""
+    c9d9c939fb01921a;
+  e77022907dd1dff7dac5c9941d
+    26
+    71bafd3a810cb7fe;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0
+    fa579abf1f086cd6;
+  a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff
+    de36e64b775dcb5c;
+  77bf79192a5b50
+    ""
+    7d4dff89fcd86251;
+  ade5d9cd739a3d
+    1f
+    8ebb09e514e0fff8;
+  337f29549e6b0d
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f
+    c079db9ba9f93c6d;
+  2dd88374d8cde8
+    e160ad10997a21635c6d62c9269029df3e6057
+    c57695c67af0e83c;
+  acc87638f508046733d9
+    ""
+    26c7bc682ced6dd4;
+  ff61cdbda3b3e9878731
+    eb
+    d26aadbc23507937;
+  fedd4705e505da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    2b121397d4ba05e3;
+  966f27043eb621b7f65b
+    000961040ef2f9b2fc5fa450727a9b542cde52
+    06d48234005d0d34;
+  ebfda19d0ccc520f21
+    ""
+    ddc6b8ce28333159;
+  5eb57bb3a4f3ebbbb1
+    8a
+    e5a427c9e3c9b30d;
+  c6c95a97a48030370c
+    33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    3994c72240c20e84;
+  5faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b9458630
+    ac308d1e150a1c6e;
+}
+
+tea-ccm {
+  60d7bcda163547d348b7551195
+    e77022
+    ""
+    ""
+    ""
+    530b9b73;
+  907dd1dff7dac5c9941d26d0c6
+    eb14ad
+    56
+    ""
+    ""
+    0b824023;
+  8f86edd1dc9268eeee533285a6
+    ed810c
+    ""
+    9b
+    61
+    1cfad40f;
+  689daaa9060d2d4b6003062365
+    b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9f137120634c95198
+    48a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e
+    9e8ba32c68560a3f15c30cf5a03a842fd9b0fa0efe2cab90
+    1380f2213a0ab1b6;
+  6b0d27a4ba234085406a613651
+    2061f7080c
+    c07df0591d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbd
+    eb7a05983eb9b9015770af0d2c48f693102f1b74249ce318fb8cc63b25
+    5624c3dd7fbb9480;
+  a3b3e9878731eb
+    fedd47
+    ""
+    ""
+    ""
+    4567c460;
+  05e505da1435dc
+    eaa7b1
+    cc
+    ""
+    ""
+    f8bc87fa;
+  49ae1d50c38201
+    a89447
+    ""
+    6b
+    50
+    e52efea4;
+  3f102b752eb952
+    9533966f27
+    043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a
+    66f563e434c693a453b8d671eb3028567196efe3862247b5
+    2189a607137658bd;
+  97a48030370c33
+    d090c54215
+    abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    aee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed
+    a17d9633a5629dc6336820d8bcdee53caa4989a877fd040f523603f3dd
+    dd98b6ad547d14c2;
+  54154f8f28523c03d4de
+    160015
+    ""
+    ""
+    ""
+    8cd54796;
+  7846b710ee72807a2219
+    bfb474
+    fd
+    ""
+    ""
+    4eb0f5a5;
+  71d891f24bb65d156325
+    9f9eb5
+    ""
+    3b
+    d6
+    ed17ae0a;
+  571ea629c54d57dd2d42
+    f70800df9f
+    cbaca48b77dba189196d1ebba10b0467cb9fc2712a199e53
+    3fa9156308cdec3f768281e040a9b9a222bd689aef66f530
+    a56c65d5ded200e4794f3478f6774dc80e78ebd4ab58a107
+    12c12c76eaf729d8;
+  6ceb0c6b08ac8b0a2226
+    0c571b4a42
+    bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b
+    6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b
+    5fc52790c2df7b9f044c3e6316146e03002f98398cedd18400504685c0
+    6cc3f23b70f9e36e;
+  5337685a96ed65b9ac
+    a33852
+    ""
+    ""
+    ""
+    b0ad3d08;
+  7ef19b09c063c46f88
+    de9fd4
+    1e
+    ""
+    ""
+    97501f94;
+  72d7b97e23e6eabdff
+    3bcd21
+    ""
+    14
+    1a
+    25f269c4;
+  99268878dbf30f1dad
+    89d4b9b120
+    12e4713df46795630e7952d22bb02d7100b8b649377d20a8
+    f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b7
+    0d3a7ed00ed5d1408dc96af9770a20b7e9a64569ce57c57a
+    48de48bb0f882042;
+  0d30ce2f1fef6ef315
+    d079839180
+    5da08da3aefc5f8584b7c5e617669c0f16e398
+    15d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c
+    41f84b6002f879d39df0797e355cb3a57a3fe6fd635c0daec81ebc831f
+    79c9b18e32ba64e1;
+}
+
+tea-eax {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    dd6dedcd5275f77b;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    0601c82ec2fc3944;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    d7f75b8b18dabaab;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    42
+    39a3b75cfe30c3e2;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794
+    846ecfa14a7130c9f137120634c9519848a877ff77bf7919
+    2a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    0f7263dd0709bb15fa04b8a0a27fe19b40e69596e2f7797d
+    f6a7ce18a023f8e6;
+  406a6136512061f7080cc07df0
+    591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    ddfb3fac295c9dd9307d5d1464f7b9f9d318b0e3e08fdd6f753b17e248
+    b9850b3a65c973e7;
+  05e505da1435dc
+    ""
+    ""
+    ""
+    ""
+    dc9b34fb8f76a62c;
+  eaa7b1cc49ae1d
+    50
+    ""
+    ""
+    ""
+    a3f9e0e94be8cc0e;
+  c38201a894476b
+    ""
+    3f
+    ""
+    ""
+    a34f5355471f105e;
+  102b752eb95295
+    ""
+    ""
+    33
+    ad
+    53d51c56bd3a3ee2;
+  966f27043eb621
+    b7f65b000961040e
+    f2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215e
+    b57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215
+    bd62aa1bd2f58df364ecf889d4ede278c68a786cfa817416
+    69a5bc7134f4df07;
+  abd6b3ad54efc9
+    a38378c5b93bf4
+    f2aad2605faee2b03fb648e27fff63102758fe
+    2b69ac26afa3349829b94586306fed54154f8f28523c03d4de16001578
+    345be4b0614ed2b6cee8f1d10f45f48bd6733ffab61b6f5a4fb978b66a
+    6e7e6f6f73563d4e;
+  46b710ee72807a2219bf
+    ""
+    ""
+    ""
+    ""
+    6eedc1098c543339;
+  b474fd71d891f24bb65d
+    15
+    ""
+    ""
+    ""
+    fb16881264b9b3b2;
+  63259f9eb53b571ea629
+    ""
+    c5
+    ""
+    ""
+    753bcc1f76e8e1d2;
+  4d57dd2d42f70800df9f
+    ""
+    ""
+    cb
+    1b
+    3eea24f4c849250a;
+  aca48b77dba189196d1e
+    bba10b0467cb9fc2
+    712a199e533fa9156308cdec3f768281e040a9b9a222bd68
+    9aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb23
+    78cdf18395582eae53580e5c7509bf60c8726dece28af741
+    5be9c10405f17081;
+  3bfa6a5cfb0bad7d9521
+    4ade49cb3b6f5f
+    e8368131115c037ba323fe1dc8151784873f0e
+    b5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88
+    df834e65b1c814814d99f141cdbb8c2d201f47551689b9561f73df1a8d
+    0b3460ba12e05a4a;
+  de9fd41e72d7b97e23
+    ""
+    ""
+    ""
+    ""
+    5532b9006b4c1a14;
+  e6eabdff3bcd211499
+    26
+    ""
+    ""
+    ""
+    9dc4ef03a759716f;
+  8878dbf30f1dad89d4
+    ""
+    b9
+    ""
+    ""
+    abd0dd2ce24924b7;
+  b12012e4713df46795
+    ""
+    ""
+    63
+    e0
+    5d2cc18653d26e6b;
+  0e7952d22bb02d7100
+    b8b649377d20a8f0
+    83455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d
+    30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5
+    a4321bcfe7f507eeced0ef16c59adb7010401f57d14a172a
+    bb947e016b25ce84;
+  e617669c0f16e39815
+    d4e9cfce3ed1ec
+    df3d264a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed1
+    39f472084e8a3a053d250ae58c6a88e6313311f092a388c01ed590e3be
+    62fab90c78f1e4d7;
+}
+
+tea-gcm {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    104863c1b7cc0364;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    6824d44998ad5200;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    2be3fa8881eb57e1;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    06
+    7ccc0eb121d76855;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794
+    846ecfa14a7130c9f137120634c9519848a877ff77bf7919
+    2a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    ccf001b2a76cd3c5568865d926c0c3c6289456233782bb6d
+    b4afc9476231f8db;
+  406a6136512061f7080cc07df0
+    591d8fa2
+    1f2dd88374d8cde8e160ad
+    10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9
+    556dc3cce065e32fd3631b31687e116db7a457f59687e62ec3b9e0f3713456edfd
+    c05e7bc1c66c2194;
+  878731ebfedd4705e505da1435
+    dceaa7b1cc49ae
+    1d50c38201a894476b3f102b752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52eb
+    65c59d689cade0038ba31ee851008842af4971efd43a6c0c83b662e9a7
+    53170fb69a4358c4;
+  fda19d0ccc520f
+    ""
+    ""
+    ""
+    ""
+    353b4c25eb464d16;
+  215eb57bb3a4f3
+    eb
+    ""
+    ""
+    ""
+    f0b9141e092436ba;
+  bbb18ac6c95a97
+    ""
+    a4
+    ""
+    ""
+    5a56e7ab195dff15;
+  8030370c33d090
+    ""
+    ""
+    c5
+    63
+    0ebbd392dd296be9;
+  4215abd6b3ad54
+    efc9a38378c5b93b
+    f4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de160015
+    89fbccd054ce4e0e729a9348449702044abe666342d15dee
+    09c94f26212a5c9c;
+  7846b710ee7280
+    7a2219bf
+    b474fd71d891f24bb65d15
+    63259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebb
+    62666b6deb78f4ca61a19405496b18f9af1e6c16c03eeafed378c6c14dc2760f87
+    5c37f56a50aad8ba;
+  a10b0467cb9fc2
+    712a199e533fa9
+    156308cdec3f768281e040a9b9a222bd689aef
+    66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad
+    e44a6687f1516bda0c8403c0befbf7537a4cf036dcdcfd96e11d2dfda4
+    26338cb7a4856da3;
+  7d95214ade49cb3b6f5f
+    ""
+    ""
+    ""
+    ""
+    d2ea2800e7d48c03;
+  e8368131115c037ba323
+    fe
+    ""
+    ""
+    ""
+    9f49f14465230250;
+  1dc8151784873f0eb5b6
+    ""
+    47
+    ""
+    ""
+    1844b6087e8cca0f;
+  da6794c18b5337685a96
+    ""
+    ""
+    ed
+    8f
+    7aa8c91ba90be3c4;
+  65b9aca338527ef19b09
+    c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89
+    d4b9b12012e4713df46795630e7952d22bb02d7100b8b649
+    d493f349ac86d68f2b5a119280b7e849a4fc67d29b952c51
+    edf814101fdece49;
+  377d20a8f083455b663e
+    4ee1315f
+    3c8f2aebfa921451dcd1af
+    5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f
+    72fde1faae8cceca80d4d76992f2636732bd05609713442fbf159576f9cb844e91
+    c654365e3cecad77;
+  16e39815d4e9cfce3ed1
+    ecdf3d264a7f16
+    cb16c2e815f422cdf0c8e30308be3c31e6bc58
+    c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a87
+    e28f18dcf71cfb49b094dac380189402100d4256169995d2f33dce3e77
+    c86e61eec92dda36;
+  4498ad0abef8bc4fcb
+    ""
+    ""
+    ""
+    ""
+    4b7087b7ee345d6c;
+  70e27e98ef1f0446b4
+    2f
+    ""
+    ""
+    ""
+    9c586b9f2a4a8338;
+  b144d44b6d00f06dc1
+    ""
+    88
+    ""
+    ""
+    f9c5a60277aba1ef;
+  d472a784e0c6f21195
+    ""
+    ""
+    a3
+    01
+    0546d37e096d7325;
+  b9f4ae985511265feb
+    d11c164720eef9eb
+    1c8dd0b00951f284649016ed00456331854bc78bf43966eb
+    0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc
+    c579381ec4d7849aa0c7959d8b5fa316430a709bf6949cbb
+    479c8f6f98bf9a02;
+  2810d858cbbc8424d1
+    26b807e6
+    daa089c3f9099c5ffb8241
+    73d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db
+    6aa3da0c805ece511ebb54408d1529d4d5f993373fbba6425692a5a643b6e6cf5d
+    f2b2f11c0f79c16c;
+  8f48af65f7cc9e3fb9
+    0e1721b730374f
+    fc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f09
+    ee503d12aef7e05140a33551f93a02eb6631e56e47a61f61b5357a4636
+    4f584686113ded23;
+}
+
+tea-ocb1 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7
+    ""
+    ""
+    ""
+    0282d13eb3775978;
+  dac5c9941d26d0c6eb14ad568f
+    86edd1dc9268eeee
+    53
+    ""
+    ""
+    9b0cdcfa8c04a747;
+  3285a6ed810c9b689daaa9060d
+    2d4b6003062365b0
+    ""
+    a5
+    3b
+    cdfabcc04b5d33e6;
+  4364c76c160f11896c4794846e
+    cfa14a7130c9f137
+    ""
+    120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    68cf0d4fc52e5f441683c80bdaac28743382b75271027f73
+    10e9f17c3d7446da;
+  1f337f29549e6b0d27a4ba2340
+    85406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    21635c6d62c9269029df3e6057acc87638f508046733d9ff
+    f5899357e4d68a1947927de3a88c20b0a372611945f68d3a
+    172008bf86d64904;
+  61cdbda3b3e9878731ebfedd47
+    05e505da1435dcea
+    ""
+    a7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    1871ca08dc9d4856d3181c8a16b9a5284e727cc4c21ee458e65a7ede72
+    400b866405f8cca1;
+  21b7f65b000961040ef2f9b2fc
+    5fa450727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b9
+    8845244bc553c66cbcd7398a529004c22b7bc44b8c12ee1cdae4b9964f
+    11437ce8e831d965;
+  3bf4f2aad2605f
+    aee2b03fb648e27f
+    ""
+    ""
+    ""
+    b24fea9cbe55c7cf;
+  ff63102758fe2b
+    69ac26afa3349829
+    b9
+    ""
+    ""
+    172ba721b939b9e3;
+  4586306fed5415
+    4f8f28523c03d4de
+    ""
+    16
+    56
+    8f3914c03d77623e;
+  00157846b710ee
+    72807a2219bfb474
+    ""
+    fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d
+    1f489e532c4895221fb87757559418ebdbb80731a4d433ca
+    aee9886723bcf8c2;
+  42f70800df9fcb
+    aca48b77dba18919
+    6d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f76
+    8281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22
+    003b1897c5b5c2a68a1061f67ab282ba4f5bc1d5b69dff33
+    d5d03c8ceb5dedad;
+  260c571b4a42bb
+    8fdb233bfa6a5cfb
+    ""
+    0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc815178487
+    616c9b723ce2dbf6582926c0082396983b36136650dbe54d4034e80c81
+    f272e48012ecedb1;
+  3f0eb5b647da67
+    94c18b5337685a96
+    ed65b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012
+    61107d0d71b63c91fc60d6981a7b027175f951198ead98054f3c891a56
+    f0b7270b5db81fec;
+  e4713df46795630e7952
+    d22bb02d7100b8b6
+    ""
+    ""
+    ""
+    8ec34345774654fe;
+  49377d20a8f083455b66
+    3e4ee1315f3c8f2a
+    eb
+    ""
+    ""
+    9752407ae0186131;
+  fa921451dcd1af5813b7
+    0d30ce2f1fef6ef3
+    ""
+    15
+    81
+    1beb2958c9f181a1;
+  d0798391805da08da3ae
+    fc5f8584b7c5e617
+    ""
+    669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e8
+    76b4c7ff71df213ad4bacdd80c69f7e6dea704bfc63d27ba
+    dbdc98bafb6d3cd3;
+  15f422cdf0c8e30308be
+    3c31e6bc58c0b7ca
+    dcb658b970e47479a684b5aefa69a4cd52147ed12ca98698
+    1a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d4
+    aff8e168c9ca00f7a3686535f2c3a87b87554ef97829cfdc
+    5a0258fedb40c24f;
+  4b6d00f06dc188d472a7
+    84e0c6f21195a3b9
+    ""
+    f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00
+    b9d9161aaec022635a134ed7847aec38d0c8903ef455fa741bf671369b
+    625dbf5d69c3e31e;
+  456331854bc78bf43966
+    eb0cfa9138ddc399
+    08445608fe95e81c2533e31c9c1a9851bc2810
+    d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f
+    8a2521cc4a159578267a2501822161dab72ff8663eeb7c0216e8e372cb
+    74098a7f405219bd;
+  30cbb7f0e4a973a8cd
+    190107314717a774
+    ""
+    ""
+    ""
+    ea4da20a4cb1c61f;
+  56f3ff669c732b58db
+    8f48af65f7cc9e3f
+    b9
+    ""
+    ""
+    0db86f6d6832d301;
+  0e1721b730374ffc9b
+    c597f56ccbb2f294
+    ""
+    b3
+    32
+    7275eb9aee00342a;
+  8766fc69f6a9f2c094
+    5ffd505003cc0cae
+    ""
+    9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65
+    d09b91ddba2620cd1a4a7fe88de8c22ef06be7a9b1627b4b
+    b37e8c04b73654d2;
+  cc1770a18cbfe6effd
+    1ff6778554acf127
+    0485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b
+    480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a
+    962273e83ac507e225ed07a9fce44bf2dbaad409592ebd49
+    0a77a4eaf298a242;
+  3e8128f8743d16687b
+    7bb8deb9bd205b70
+    ""
+    e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677
+    795b6ec2108ac4cbda8b87ede294541cfdb7240cfae8ff7a4d9a474ea5
+    798360c72cf9d7d0;
+  508a15dde524af3e2b
+    ee0646541a42c2ec
+    ccb44d65bad397abfaf529ee41cf9a05c7efed
+    ef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a
+    f0d9c8a507a51d66a13e9cd477b177773ff6f94dbda67dbf07003162ab
+    70ddae5e6ffa478f;
+}
+
+tea-pmac1 {
+  60d7bcda163547d348b7551195
+    ""
+    25bca2fe99e75c4b;
+  e77022907dd1dff7dac5c9941d
+    26
+    5b87dc7b2acac1be;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0
+    6889c9fb6030676d;
+  a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff
+    453581670da49ebe;
+  77bf79192a5b50
+    ""
+    613c5d3427421aa4;
+  ade5d9cd739a3d
+    1f
+    39649926ad4cd68d;
+  337f29549e6b0d
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f
+    24043405966f7f84;
+  2dd88374d8cde8
+    e160ad10997a21635c6d62c9269029df3e6057
+    8242433c45487ffe;
+  acc87638f508046733d9
+    ""
+    f24ce66e0a3a63d2;
+  ff61cdbda3b3e9878731
+    eb
+    8bdfb1992aed4edf;
+  fedd4705e505da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    ee6d2bd9a43a054a;
+  966f27043eb621b7f65b
+    000961040ef2f9b2fc5fa450727a9b542cde52
+    936eb156c9146198;
+  ebfda19d0ccc520f21
+    ""
+    c33c9c35b8f3836e;
+  5eb57bb3a4f3ebbbb1
+    8a
+    ac3f52785c36bf6f;
+  c6c95a97a48030370c
+    33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    1a935b87b899b277;
+  5faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b9458630
+    df79e3c4601f609a;
+}
+
+tea-ocb3 {
+  60d7bcda163547d348b7551195
+    e77022907dd1
+    ""
+    ""
+    ""
+    50e56f25fe9fa75a;
+  dff7dac5c9941d26d0c6eb14ad
+    568f86edd1dc
+    92
+    ""
+    ""
+    b018725e1da1fc14;
+  68eeee533285a6ed810c9b689d
+    aaa9060d2d4b
+    ""
+    60
+    94
+    bce5f4718c762d22;
+  03062365b0a54364c76c160f11
+    896c47
+    ""
+    94846ecfa14a7130c9f137120634c9519848a877ff77bf79
+    f63c61926eb91517997efd1a280da07726f45280bd3d5893
+    ce2fa9afb1a39afb;
+  192a5b50ade5d9cd739a3d1f33
+    7f29549e6b
+    0d27a4ba234085406a6136512061f7080cc07df0591d8fa2
+    1f2dd88374d8cde8e160ad10997a21635c6d62c9269029df
+    3f60ebe2319bfad8b557bcd414b60e89212bbeea2a5c4373
+    74e2d32d1767921c;
+  3e6057acc87638f508046733d9
+    ff61cdbda3b3
+    ""
+    e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a89447
+    b04de9996b330715ff382cfec0333bfd66421410bf16459d12a0f28f53
+    38b0c98a1f1ec6da;
+  6b3f102b752eb9529533966f27
+    043eb621b7f6
+    5b000961040ef2f9b2fc5fa450727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c
+    f7e226026675e1adc5cf37952abccc77b8154368557b87ec40477620f8
+    44b45cf50973cb50;
+  33d090c54215ab
+    d6b3ad54efc9
+    ""
+    ""
+    ""
+    1eb02bffdd9d7dc6;
+  a38378c5b93bf4
+    f2aad2605fae
+    e2
+    ""
+    ""
+    58ee8252984db2d4;
+  b03fb648e27fff
+    63102758fe2b
+    ""
+    69
+    d4
+    961e871fd84b5a74;
+  ac26afa3349829
+    b94586
+    ""
+    306fed54154f8f28523c03d4de1600157846b710ee72807a
+    0e6295372bd9df61b2ca8d2a383154e2c70fd3ca68805de6
+    b8a6cce0dd7f6222;
+  2219bfb474fd71
+    d891f24bb6
+    5d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcb
+    aca48b77dba189196d1ebba10b0467cb9fc2712a199e533f
+    fd0562d5b003e68f0d1d72c4e082b87827f85ee88b52cd87
+    1e835d35eb0cd334;
+  a9156308cdec3f
+    768281e040a9
+    ""
+    b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb23
+    41c1cd96958e4f6ffaa16db2ec8a521140e548564fccdfb890ab8939f0
+    56271f56c7ea11ed;
+  3bfa6a5cfb0bad
+    7d95214ade49
+    cb3b6f5fe8368131115c037ba323fe1dc81517
+    84873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c0
+    fc1d24d91e4ab2c51590e2a94796bf4da4a50a6c07e20a40fb1981d17a
+    c8e3e3fd09cfb494;
+  63c46f88de9fd41e72d7
+    b97e23e6eabd
+    ""
+    ""
+    ""
+    b222e91b3dfc4b68;
+  ff3bcd211499268878db
+    f30f1dad89d4
+    b9
+    ""
+    ""
+    ceaecf08444b8cd3;
+  b12012e4713df4679563
+    0e7952d22bb0
+    ""
+    2d
+    a2
+    d537e5734f7de7da;
+  7100b8b649377d20a8f0
+    83455b
+    ""
+    663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f
+    4020ccd7a166229e19cd4c48b61701120098e7dad7780102
+    ef64295063a916fa;
+  1fef6ef315d079839180
+    5da08da3ae
+    fc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d
+    264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0
+    07c0c12b3fad029d165bb6b6a9363c7699a27081a8aaf72b
+    f984336df824fe7e;
+  b7cadcb658b970e47479
+    a684b5aefa69
+    ""
+    a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446
+    c19e2396ffc0dd7c73a0f53b39e90139179cefc32e75f8d50f5f627a39
+    2a57fec6502d09d9;
+  b42fb144d44b6d00f06d
+    c188d472a784
+    e0c6f21195a3b9f4ae985511265febd11c1647
+    20eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0c
+    3fb5c778395cfbfbd94d6707cb18520f9b95b101e5f1673248f37afb8f
+    01ba4da3facd1ec8;
+  fa9138ddc399084456
+    08fe95e81c25
+    ""
+    ""
+    ""
+    ef931af545c454ab;
+  33e31c9c1a9851bc28
+    10d858cbbc84
+    24
+    ""
+    ""
+    c24d1e102b084b5e;
+  d126b807e6daa089c3
+    f9099c5ffb82
+    ""
+    41
+    e8
+    3b28cf6d12081293;
+  73d7634c04226f30cb
+    b7f0e4
+    ""
+    a973a8cd190107314717a77456f3ff669c732b58db8f48af
+    27a3f2e9c0dbf9ee78fe2eaea691734d96105ec04619032b
+    552e65ed80338e08;
+  65f7cc9e3fb90e1721
+    b730374ffc
+    9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003
+    cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911
+    45aa335db92540c2bcd0ec28dd97d101c4e14776c4fd1d04
+    fa2cf5a4f20122ef;
+  e32d65cc1770a18cbf
+    e6effd1ff677
+    ""
+    8554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b
+    44c70463fafaed7e9b3de27cf5c92511a88eeaf9453b1da16914f9c61c
+    62e9efc911c2b6d8;
+  480aa3a4c84cef64f6
+    c9b53bf8f957
+    f4b03cf43e89957f9a3e8128f8743d16687b7b
+    b8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac84
+    d848b6c4ea2e04b8599c41fa786fbac28cbef5ab4039415ca71d4678c7
+    19c2d53e7566afc7;
+}
+
+tea-ocb3-mct {
+  16 cb326883e2a7abc7;
+  14 129631272316ca86;
+  12 c0a6fdaab85e1578;
+  10 112f7058a53b3c59;
+   8 786b90684bfe1e77;
+   6 842c674eb1cff4ed;
+   4 f1319ace9cb4027c;
+  16 fd0cc4fec30a;
+  14 215b15aeab0e;
+  12 f23528992843;
+  10 48cacf15625e;
+   8 74b0608cc983;
+   6 d0dd11b11aa8;
+   4 1960a6aa86d6;
+  16 b9865f9f;
+  14 6f09a6bc;
+  12 b32b1dc6;
+  10 13e1a721;
+   8 b5aefa26;
+   6 c2c46207;
+   4 b0bf9065;
+}
diff --git a/symm/t/twofish.local b/symm/t/twofish.local
new file mode 100644 (file)
index 0000000..1ec9605
--- /dev/null
@@ -0,0 +1,916 @@
+### Local tests for Twofish.
+
+twofish-cmac {
+  60d7bcda163547d348b7551195
+    ""
+    754e3b8b4c2532dd6d26b8d2f84c5052;
+  e77022907dd1dff7dac5c9941d
+    26
+    285e8d83398954587754b4811af4dab0;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    8f5bfbfe9492043376e871ff2174ab5b;
+  34c9519848a877ff77bf79192a
+    5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    1145ad608df01125e831efceb693c24b;
+  8374d8cde8e160ad10997a21
+    ""
+    1406392a843cc373790cd8696e89d1ea;
+  635c6d62c9269029df3e6057
+    ac
+    70ba3b7789c8bae0f1f51219e9730125;
+  c87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    6fa25a24102c74af333d7d00e814c926;
+  21b7f65b000961040ef2f9b2
+    fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    fa27b530c2b27564a3be2411d2eca2ff;
+  4215abd6b3ad54ef
+    ""
+    ed98c8e1a4135fa9bbde6733062c0be7;
+  c9a38378c5b93bf4
+    f2
+    ebc7a731525279b9f3432af13aa735d1;
+  aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    ad157b3ad3c9b514307a6075859baa83;
+  bfb474fd71d891f2
+    4bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9f
+    2c6b7e9737106b483e1ca8497e995b5a;
+  c2712a199e533fa9156308cdec3f768281
+    ""
+    0b25455053592925387a5cab03aa3418;
+  e040a9b9a222bd689aef66f5306ceb0c6b
+    08
+    795defa6334cf18ed76ffa59a9ef6500;
+  ac8b0a22260c571b4a42bb8fdb233bfa6a
+    5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    7a1639ba51eb2aeaf469d4980148378f;
+  b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    dabc6ab5c4f7051e8211bcafd27650f6;
+}
+
+twofish-ccm {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9
+    ""
+    ""
+    ""
+    b0c9e428;
+  941d26d0c6eb14ad568f86edd1
+    dc9268eeee533285a6ed81
+    0c
+    ""
+    ""
+    68f3bf5a;
+  9b689daaa9060d2d4b60030623
+    65b0a54364c76c160f1189
+    ""
+    6c
+    c6
+    30270248;
+  4794846ecfa14a7130c9f13712
+    0634c9519848a877ff
+    77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    f3d43c102dc21b52ba97431dbe9d96795b0c6d04920b5477e6ebf4706786e1bb6bf172fa749e9f62041c7b697875d4ee
+    89a2a9f68c8a775f6d0ad66e43bfc2b5;
+  05e505da1435dceaa7b1cc49ae
+    1d50c38201a894476b
+    3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0c
+    cc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad2605faee2b03fb6
+    13d35753fc8ea503aa2f2ce83e66c54c392aeab215aacd566043634da890cac0f81e7318c2640f2ccbdf691baf4e36e42d48a992a2
+    0337b188fc02b7868b5f6c0b9c462f44;
+  48e27fff63102758fe2b69ac
+    26afa3349829b94586306f
+    ""
+    ""
+    ""
+    f3b74c76;
+  ed54154f8f28523c03d4de16
+    00157846b710ee72807a22
+    19
+    ""
+    ""
+    0efb24c2;
+  bfb474fd71d891f24bb65d15
+    63259f9eb53b571ea629c5
+    ""
+    4d
+    fc
+    2f1984e1;
+  57dd2d42f70800df9fcbaca4
+    8b77dba189196d1ebb
+    a10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c57
+    1b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da67
+    6a399a08440ac7cb9d502c9f52a33d1df8ee9681bab13cfa2cae7aaeb82071cd7c99df8f768be5f910cf8db83e09f14c
+    2ed58e267c0b2588e3910f0c31b961d3;
+  94c18b5337685a96ed65b9ac
+    a338527ef19b09c063
+    c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e
+    7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d079839180
+    7aa91272a3c0c35156125064eb307c2e5bfe698266b7effff016afe64776bcc38d6965424f882285c418a92f480c24c59fcb2c1f79
+    6b3f9910b25e356ecfac4863fcee37d3;
+  5da08da3aefc5f85
+    84b7c5e617669c0f16e398
+    ""
+    ""
+    ""
+    b17a3a3d;
+  15d4e9cfce3ed1ec
+    df3d264a7f16cb16c2e815
+    f4
+    ""
+    ""
+    d95d0468;
+  22cdf0c8e30308be
+    3c31e6bc58c0b7cadcb658
+    ""
+    b9
+    c7
+    0ef68941;
+  70e47479a684b5ae
+    fa69a4cd52147ed12c
+    a986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae98
+    5511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608
+    b0710f1564a118168643f2365349548ad8955fb798437ec62b9b3005d68ffc8e50ea0b92e3c7fe92c0c0660ec9945182
+    e2d3128d41c1f5f53fd1727fe0b0b097;
+  fe95e81c2533e31c
+    9c1a9851bc2810d858
+    cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a7
+    7456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0c
+    fc551743341d475b9daee5768d456ab9a1e4c4156650b10689702560de27cc285a543e06e6f0b8e3e2868deba6ea47016e54a72bf5
+    169d69aa85a8d2806a324ea9568094fd;
+  ae9ce021a5f1fa4ffa91544485f1a1258b
+    2b9b8f0911e32d65cc1770
+    ""
+    ""
+    ""
+    eb7833ed;
+  a18cbfe6effd1ff6778554acf1270485b2
+    03a3c1c4c967c0a458cb94
+    8b
+    ""
+    ""
+    2d96cd56;
+  dd409b687fa3a6827b480aa3a4c84cef64
+    f6c9b53bf8f957f4b03cf4
+    ""
+    3e
+    12
+    5739e99a;
+  89957f9a3e8128f8743d16687b7bb8deb9
+    bd205b70e04c091d20
+    5cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397
+    abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107
+    9a42a39fcbb079b601c9a0169b11a7bda9592f85ee47a7cebf8be2dad4157356aedf18d3c792446f2439a0cf0d95e7f7
+    37724239996c480fc49e7e43a84458bc;
+  c8e7d715a92add9589d1f5c054b2d98351
+    4605ec590294a319b9
+    802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee
+    1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44
+    0dd51ef8b16e3923be6906378e726f6e9d4b79b815fdad7282db135ee1d65a9b89f08c2976c77be0c5d76cdc530cfe077e71bfac9b
+    d086f21e917aa8b0152b51116a8d72af;
+}
+
+twofish-eax {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    9c340a7f586dfd6561333d865d3be637;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    b49707150b501a9aeb08849a8ce835c5;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    7c390db5bff614ee888d1b5a9d58a08f;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    19
+    747cff93ab194812482ac265aae10c05;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9
+    f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7
+    080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61
+    dd91fa89b463675215e5bf946e26d943bec9f16b85ab13386e59e241b8040179b9434123c3f18a91db1ca422e5ec4589
+    2516f3bef1bc5bc211b49bed94687265;
+  cdbda3b3e9878731ebfedd4705
+    e505da1435dceaa7b1cc49ae1d50c3
+    8201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    edf0e0b4ca907432f7c994c4d185aa3db5d998ad1911852793c31f1e08c8a0facb5b743188745f1f1f0a3b5cb459a49b6568ade9d9
+    a8755cc0ba6d7951c1e462f3d7488839;
+  5faee2b03fb648e27fff6310
+    ""
+    ""
+    ""
+    ""
+    fabb71671ec2e89032276be01704ef69;
+  2758fe2b69ac26afa3349829
+    b9
+    ""
+    ""
+    ""
+    560eafd0ed251ac82b143a85f180b657;
+  4586306fed54154f8f28523c
+    ""
+    03
+    ""
+    ""
+    94fafa14c9819062fb631fb20d784aed;
+  d4de1600157846b710ee7280
+    ""
+    ""
+    7a
+    a8
+    db105495b660dbd22506ea66be1d09d5;
+  2219bfb474fd71d891f24bb6
+    5d1563259f9eb53b571ea629c54d57dd
+    2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222
+    bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe836813111
+    947c775e1a6deb3042c702a3600473796bebeb264ff0594b0352a85491239c812fa2f3c21d458e2b5b784625e5f8cc32
+    8e0728b45016d6178f32ee80773b72d0;
+  5c037ba323fe1dc815178487
+    3f0eb5b647da6794c18b5337685a96
+    ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89
+    d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d
+    1d131416240ea96f731942579422e18acb633d0429a46d31b64ff5f24f8ee6bb05769731eaf0da2725da3204f04820baf228831c09
+    e21621e777b6283f5fbb2095f4d9a668;
+  30ce2f1fef6ef315
+    ""
+    ""
+    ""
+    ""
+    52512330b00f2450fdfcb97d554ac098;
+  d0798391805da08d
+    a3
+    ""
+    ""
+    ""
+    58800f1e6613f646fe7e562590c3de9f;
+  aefc5f8584b7c5e6
+    ""
+    17
+    ""
+    ""
+    72cb0d5710a6a99ba7618544108409ad;
+  669c0f16e39815d4
+    ""
+    ""
+    e9
+    69
+    05f8ecb88a66f4a0289e5e3d04bddbe7;
+  cfce3ed1ecdf3d26
+    4a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98
+    ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb1c8dd0b009
+    772117eeb7a3c0f1901d15bb4cd5aa2bbcc21c8900e9a590918c1278893bf93d6e10908d6aa0a3844de33ae47ef11fbf
+    463ada14035a59434547a76404af4ee6;
+  51f284649016ed00
+    456331854bc78bf43966eb0cfa9138
+    ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb82
+    4173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3fb90e1721b730374ffc9bc5
+    5f7a453a5988894d4c010d0c1d61c46e0fdac102b82d40e60fd88fa2a733048be1adc091040977c1ce28b608f3b47f541316a51382
+    b3e874d11f8b935d338bd549a4d8158a;
+  97f56ccbb2f294b38766fc69f6a9f2c094
+    ""
+    ""
+    ""
+    ""
+    522cec98b8703b39bdef4b7b71100e69;
+  5ffd505003cc0cae9ce021a5f1fa4ffa91
+    54
+    ""
+    ""
+    ""
+    9696c681b07c07a545c546a9698822fb;
+  4485f1a1258b2b9b8f0911e32d65cc1770
+    ""
+    a1
+    ""
+    ""
+    e99931b41ebf63d52cb833b03c3f6ea4;
+  8cbfe6effd1ff6778554acf1270485b203
+    ""
+    ""
+    a3
+    53
+    c4f447d9deadfeb7916af9eb906f838d;
+  c1c4c967c0a458cb948bdd409b687fa3a6
+    827b480aa3a4c84cef64f6c9b53bf8f9
+    57f4b03cf43e89957f9a3e8128f8743d16687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac
+    8451399587011677508a15dde524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef340153
+    ca3c5595f62889c4f242ac0da256bf103ca30908909139a4d43b0baa411a6fe47f8daf20b32bcba14f482f76b888265b
+    041cf6ef9deec56c1bba923f276f8d75;
+  9c51d2a90bbf7f1bfc338ab0ef5746ea8f
+    dcccd213e33f7e8a5718fd25014107
+    c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7
+    ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7ab
+    1cc781e5396ac8524f32f3a2e1dd087ce19381548225aa1d043499e04890a78ba1c21cad856ff355265a9760b6f81ba5a9b34d275f
+    bb1cd29c56a26e0a9ef3fc8341f8f663;
+}
+
+twofish-gcm {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    7e0c01ab8086fe01a7c940e3d5e4c825;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    03cc1ef1b342e6882d46938c5583bcde;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    922c01776999bb27557eaff4621e6542;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    2d
+    65db54152b66c0a4630723dad69c59fe;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9
+    f137120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7
+    080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61
+    d2fd5ce98fff00c787eec5ba7c1428b7e298c61467e66996e9e34dd9f98e9dcb9e272339bcd0b5e261887f4a735d14e5
+    bdee54527341a497d08ead912a0fd02b;
+  cdbda3b3e9878731ebfedd4705
+    e505da1435dceaa7b1cc49ae
+    1d50c38201a894476b3f102b752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33
+    7666e42e7493950c9783e8b919586b513c70b5ac09fcfcdd0a7199a12fded4b8c7499bc5803a2eb9c0e3934a4f42ff8fe32fad10326556567e
+    c341241121b63236496060eef63ffe36;
+  d090c54215abd6b3ad54efc9a3
+    8378c5b93bf4f2aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee
+    72807a2219bfb474fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b04
+    5f0cf7d078722238b7aaac66bf90a3a9761e66f896d956d9414d54a425e983126667ab8b776f1363fc275661175db1ee73d5529c59
+    0e29764305b7acf72af4b12db37fdb18;
+  67cb9fc2712a199e533fa915
+    ""
+    ""
+    ""
+    ""
+    dbe0886648906617f156b7749baf20d2;
+  6308cdec3f768281e040a9b9
+    a2
+    ""
+    ""
+    ""
+    d250af0db768e3345e8cb717015d4481;
+  22bd689aef66f5306ceb0c6b
+    ""
+    08
+    ""
+    ""
+    11cea01fc59f767221b1d1f2d0143b96;
+  ac8b0a22260c571b4a42bb8f
+    ""
+    ""
+    db
+    51
+    2d05a8a0ba680cee9cd48e338c8b48a9;
+  233bfa6a5cfb0bad7d95214a
+    de49cb3b6f5fe8368131115c037ba323
+    fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88de9fd41e72d7b97e23e6
+    eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d7100b8b649377d20a8f08345
+    0499046ea761b7f3aa662f3bde9f5f0c37f36bb3fb0d364b585c4d2b0e4f4a66153fba1b366ac0c79439aeca1967adb8
+    8d5c3aac36d523729b5afb91924ee629;
+  5b663e4ee1315f3c8f2aebfa
+    921451dcd1af5813b70d30ce
+    2f1fef6ef315d0798391805da08da3aefc5f85
+    84b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684
+    ef0a5118e770a0a6ab603d85ad16ffecfc3e84c9c4e6390c6a658ba226d4f85ed42d57e886a1076bdd9ffae334371a545add74a74a6e59c7fb
+    79064ad707bf5bb9f2443064d63635af;
+  b5aefa69a4cd52147ed12ca9
+    86981a874498ad0abef8bc4fcb70e2
+    7e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720ee
+    f9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d8
+    83eadff65bdc0a99b0c11b2414491643ef798658f9a4a2c78a46c89ca7476745450aaa0add25c28bd3c0eefeac9e7f19f3d95904d0
+    10317aaa71d95a323784406eecfc6621;
+  58cbbc8424d126b8
+    ""
+    ""
+    ""
+    ""
+    4108dabb7754ccdf2f498097fe2493bb;
+  07e6daa089c3f909
+    9c
+    ""
+    ""
+    ""
+    d2b1658dfe8f7e211bf9f3bee32064a8;
+  5ffb824173d7634c
+    ""
+    04
+    ""
+    ""
+    ab2e2975c1c3b9bc07bb7b2c7a3f55fc;
+  226f30cbb7f0e4a9
+    ""
+    ""
+    73
+    51
+    104b6be42e4ebbd2b94e5da48806507a;
+  a8cd190107314717
+    a77456f3ff669c732b58db8f48af65f7
+    cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0cae9ce021a5f1fa4ffa91
+    544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a458cb948bdd
+    8b86c6c7e623c9e343ae7b1fa3d1eb8d38263234e881594a86fa291136d838ea2326aab6f331ed8241dc5632ab3dd10a
+    b0a96f29b83f2b02056bf2e94ac43147;
+  409b687fa3a6827b
+    480aa3a4c84cef64f6c9b53b
+    f8f957f4b03cf43e89957f9a3e8128f8743d16
+    687b7bb8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677508a15dde524af3e2bee0646541a42c2eccc
+    96544d398a17314d02e7345a80062864904f86b8ba0280f29064775fb7669b6b2fc8f7e9b1fa6a213ec25349802826b9a6148ef2954df0a019
+    c7a2ce4d1d3d9949eabebe7a572a5f7c;
+  b44d65bad397abfa
+    f529ee41cf9a05c7efedef3401539c
+    51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c0
+    54b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70d17d4569eaff59a332ba58d5d5589bfe
+    ed9ebcc7d472e5707c7102b1cf72f2330419fbc2162a8d603f0bca3963eaf35992339cbe19b1525909be51f7a4cfebcb0b20efb5e7
+    11a34ad52fc2412ffde804945f7527de;
+  079753ee1a957eb6d6699e6b7ea2725cb2
+    ""
+    ""
+    ""
+    ""
+    bfce79cd62f6cd0cd7bb988245358c97;
+  dac07ecde95759ac46fee6dda7abc8ad68
+    da
+    ""
+    ""
+    ""
+    1582dba1ba23714f141583436dbb0af1;
+  ac90cfe22d2f1f2968cc42fa8b669ed3bb
+    ""
+    35
+    ""
+    ""
+    7e202b58482cc68bee3ad6f7ccd6c034;
+  42a9cf44bbc8c6254d980398bd94e66eb4
+    ""
+    ""
+    56
+    19
+    e5560f7f46d1747af91a51b39fa2a553;
+  3d405e51881e99027b8ab9aea3ccf860b0
+    009740763d96836c5f87b95460938de1
+    288c69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c3680
+    0d9645563a308ba60076817523bd2abf1261b089d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f
+    a86b53285f02553f8eea5475249f7d19cdd539a0a2544e883ae030bdab6c626b5a459a384171205e95534a8e5c6658e1
+    6fca68ddf9bfb6b8a06b44be4bb55eec;
+  834a06148f302c3973accd56f6f24e3395
+    8b8c2e2352fd61e4fa8fec81
+    6ac861a8b33779f09e7a10fc02a8f48afa3080
+    ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578c8ec4837898a92142b5b0677da1ac273117b45bcfff5d5f8b6fd
+    25c9ca2752529fa0759c758d42f753af1a4ab5b3f036d585663ce2c886009a979951f8ea9e492a2175238be31f71aecb2a240e14be8873994e
+    944a53fbe54197cb27d46c0f768fde88;
+  e2893232a9f81d14517ffae475f6b94a43
+    a67b3d380d2f9aaafe2dd721c0095c
+    8808847689211450ba8095ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785f
+    e426a5a0e80f678d404147842941feeffdc2eb44dc8c0d5e8f444f7f4e0c893959b74dc23a7bb40e7e0013e5150686d2301b43a15a
+    365bec4034b390949b707acfee0545eb79e0b47d87cdb901af6c3e964a997fe8c0faa678fa214c8ec5887e250c0d3007b2f1e29a93
+    2fc6d2d214bcad3f502b9bf292029e1c;
+}
+
+twofish-ocb1 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26d0c6
+    ""
+    ""
+    ""
+    8d1cfee1984c2e05a4a9b88de25d0b03;
+  eb14ad568f86edd1dc9268eeee
+    533285a6ed810c9b689daaa9060d2d4b
+    60
+    ""
+    ""
+    71a0344b8fa6bcb38a5dcd91fe1ea7f4;
+  03062365b0a54364c76c160f11
+    896c4794846ecfa14a7130c9f1371206
+    ""
+    34
+    79
+    7ad05aa4fccea98135597fed29e12041;
+  c9519848a877ff77bf79192a5b
+    50ade5d9cd739a3d1f337f29549e6b0d
+    ""
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a21635c6d62c9269029df3e
+    bd4d3d7b5c177d602a76b0d30f94b746925a97ac08dbed466c21f623133b3b4a07a0cb3122bb409131b91e4891b4ad23
+    8184dd419c0d7f3c10ae44312fdf5223;
+  6057acc87638f508046733d9ff
+    61cdbda3b3e9878731ebfedd4705e505
+    da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb621b7f65b000961040ef2f9b2fc5f
+    a450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215abd6b3ad54
+    90126eb72fa9923afc3d8381c787206cc21e1c0310b3aed18859d30dcccbebf00a040d6dc4127e8993eabc5d302aea03
+    2b753135ff0238a472730691c382446b;
+  efc9a38378c5b93bf4f2aad260
+    5faee2b03fb648e27fff63102758fe2b
+    ""
+    69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219bfb474fd71d891f24bb65d1563259f9e
+    261413d3a72447a6d5ffce0583f1b4af32e7203b82f5d6e8686ab8c21873e4741a9dff70ab872edffdbe7a795a7b4b7f469f3a6de5
+    eb7184fda3922f373e8bcd6ca37d4042;
+  b53b571ea629c54d57dd2d42f7
+    0800df9fcbaca48b77dba189196d1ebb
+    a10b0467cb9fc2712a199e533fa9156308cdec3f768281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b
+    0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da67
+    c7a8156ec4894b7015e422efd4f9030c74e9e217ff1f15c02897a105a5c154391dac634298996cc30a8b383964cee203325787172e
+    646143dc04f96fe66f7b7e10e2d956c2;
+  94c18b5337685a96ed65b9ac
+    a338527ef19b09c063c46f88de9fd41e
+    ""
+    ""
+    ""
+    0298067ddb8e8ad3a35c06d9aaa23012;
+  72d7b97e23e6eabdff3bcd21
+    1499268878dbf30f1dad89d4b9b12012
+    e4
+    ""
+    ""
+    26caf5aed4068af4fcdbf0aab49387c5;
+  713df46795630e7952d22bb0
+    2d7100b8b649377d20a8f083455b663e
+    ""
+    4e
+    de
+    147491a865a55479e7820b48d65cfe86;
+  e1315f3c8f2aebfa921451dc
+    d1af5813b70d30ce2f1fef6ef315d079
+    ""
+    8391805da08da3aefc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e303
+    a9ba8b1b3a7f68575146960578aaec63e43366c7ae57e481739749d32bddde3c33c7b4c5e096c8c0a96e2cbf5adecd17
+    0eab7b499f15026215627b43e0b9c17a;
+  08be3c31e6bc58c0b7cadcb6
+    58b970e47479a684b5aefa69a4cd5214
+    7ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9
+    f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0cfa9138ddc39908
+    0dee60335c90fde30d3e167df72c778839a69219947fcafa74f9bc6c21e32904b4298c20484c010e3aee5a032e33d3c9
+    9a199af39e93cb1225d112e9c0f01d61;
+  445608fe95e81c2533e31c9c
+    1a9851bc2810d858cbbc8424d126b807
+    ""
+    e6daa089c3f9099c5ffb824173d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db8f48af65f7cc9e3f
+    e2a3d6365b19a3761fd7be55731c5b3dbce322f528a322b8c5b24453cb6a22656c944a6e304f5b3fb4b7cffdd5f87e17fe54664f5e
+    8af45bd468a49b9fb4af7dee23301b73;
+  b90e1721b730374ffc9bc597
+    f56ccbb2f294b38766fc69f6a9f2c094
+    5ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6
+    778554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f
+    9736fd0b0e9860bfb50e7d81301a7cec617bb1783e531a6708db5c790c5ffc287ce2e0f79d9a763bfff28182787061828fc2ed02fc
+    a00c4e76ab4c35fd8801455c627d2b9a;
+  9a3e8128f8743d16
+    687b7bb8deb9bd205b70e04c091d205c
+    ""
+    ""
+    ""
+    5f6ea6b0475400a164944c4a31a7547f;
+  dad9e9a79b1abf91
+    b0851e5ca605ac845139958701167750
+    8a
+    ""
+    ""
+    e55c85fb82289b89250fd9f463b50b74;
+  15dde524af3e2bee
+    0646541a42c2ecccb44d65bad397abfa
+    ""
+    f5
+    98
+    82d904459d8811b4f0907618d0215d93;
+  29ee41cf9a05c7ef
+    edef3401539c51d2a90bbf7f1bfc338a
+    ""
+    b0ef5746ea8fdcccd213e33f7e8a5718fd25014107c8e7d715a92add9589d1f5c054b2d983514605ec590294a319b980
+    ff802a1e6113b0aac88c7a76f0338e3c95fc70c98801be1476af39a21b8bc15f5cfdf6c5643a716ab23091a187014eb2
+    3b80083b38ba73e4d4bab2799e93b59b;
+  2068a9f891bc5ba5
+    afabf8c3122d12d7ff3c41122d70d17d
+    4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8ad68
+    daac90cfe22d2f1f2968cc42fa8b669ed3bb3542a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9
+    e0d20e66b71e3a13aedd139a71c5823d4fbee0d3a59e3c6414b562999b2948ee764542cfa3e846d92d2afc1f4374034d
+    379db2c942b5aae433f382256bec565e;
+  aea3ccf860b00097
+    40763d96836c5f87b95460938de1288c
+    ""
+    69d80ea12ff4bb5f069b8a2e86041c1b9fc214e9ca2186ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308b
+    be3aa26f73e11ecc3bc58559bcdb8b6e1fa772bf51cddfbcf1bda58fa77945b735ede1d04f1b0b3d9b732ce7852082e8ed98b9e63c
+    f5d209e5468ccc2e7988a33924daf18f;
+  a60076817523bd2a
+    bf1261b089d8f23a9c2835076a23faac
+    2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4fa
+    8fec816ac861a8b33779f09e7a10fc02a8f48afa3080ee119a52a9a817e4f2b94b0820cab383a8cffeea7c486315799dc875fba578
+    4bfc4201c557734332bd6162fcc0527136cd4ba9b3ea9dd265a3901551abc061862e1e1643a6fa6ae23cfce273204557d56e9e05ca
+    8c085a22b651c7c3e54710d958570722;
+  c8ec4837898a92142b5b0677da1ac27311
+    7b45bcfff5d5f8b6fde2893232a9f81d
+    ""
+    ""
+    ""
+    cc01d47fcdd2ebfd7fc167351b89c25c;
+  14517ffae475f6b94a43a67b3d380d2f9a
+    aafe2dd721c0095c8808847689211450
+    ba
+    ""
+    ""
+    b604e266d82e05f040dfa3e55dca1544;
+  8095ffab1eaadf66fd22ac1976063e113a
+    b61f813e28a1397a7974a1d7f4220c78
+    ""
+    5f
+    68
+    87c774626abd1daca5cddd7c8dcba032;
+  e426a5a0e80f678d404147842941feeffd
+    c2eb44dc8c0d5e8f444f7f4e0c893959
+    ""
+    b74dc23a7bb40e7e0013e5150686d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3
+    1f0dfa5f0c07208cf7d6e19d3b49c4335b63416bdf67eb3667d2642bcf8d8639f03c58ab865cce0f068b222eac1b3ad8
+    f580549f5cce1fae5e1df61bfd49c97a;
+  ab6cf8556b7aa776945948d1b8834df219
+    6c92ec1718dcdeee0d52d9539726d281
+    0391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e737882cd09c2b9a80f34c0fde11c2481b11fc76bfa
+    4dbf710a9e544e0c536ca1e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0
+    0efa3388b0f1344526b97696cd61d5974dd9339a37fdfd020ef6687384208deb99fb2c79a91bfcf57135ad36f60aeabd
+    12c3060b6d5cd360d29a9f8ee62bb1cb;
+  a9aabb6c4e3c3554f8fb1ef61614c27029
+    5dfc0ca6551ca4bdb75359f91cb9d921
+    ""
+    056b7de74fc9a9b37154ce6c0b396179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3d
+    e2c8468063ab076373bf2c088a0a7a9acc80937ac2f29036a733b089f5214311bf48de59cca31051ad6eeca19f34154412d3e4acbb
+    887f83fd9a8db0d28cd849e7ec0cd72d;
+  f6c2b3fac7cbcf96523d4723f91801325e
+    b8553236651c96788d73d192ee53b3f3
+    ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b59ed034a867642d25d54756fa5c47f16f64b837
+    bb4926214211a1c696ba172010abb433922a22d9fd881519165eb9d85197a21cc34ac0d5ae7be8dbf98e4ffed2cf6b1372a5aa47b5
+    6ce7de9f52ff4f4fc21a63423b6d084752f7f7dc7b4e2c7d781a7fc6c468d2ad5a694156b41e8033ef66a59606919b13435453b037
+    ef0d9a53c0eadbb12806aab80d24d67d;
+}
+
+twofish-pmac1 {
+  60d7bcda163547d348b7551195
+    ""
+    b9898ea028d9c1fb8192e585467aeff7;
+  e77022907dd1dff7dac5c9941d
+    26
+    d2547a3fa161edf4427ac2523c0e12f4;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0a54364c76c160f11896c4794846ecfa14a7130c9f1371206
+    629a79b85d3c132fa98b11bd247ae22a;
+  34c9519848a877ff77bf79192a
+    5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd8
+    78a88c6c5a799d4bf7276ef82681502b;
+  8374d8cde8e160ad10997a21
+    ""
+    142ab85c8da67eb03c02351267ac528f;
+  635c6d62c9269029df3e6057
+    ac
+    97ef82a6ab463b32b3c6de3b8858e703;
+  c87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    13e0efe3390a5696584ff6f095c9d866;
+  21b7f65b000961040ef2f9b2
+    fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c5
+    550b74f7ec72626368a2c58ce23bb008;
+  4215abd6b3ad54ef
+    ""
+    f5dd9becdd3d3fbecc3dee067bb06ff6;
+  c9a38378c5b93bf4
+    f2
+    51c108d4abf0343491d7ec7b74e35736;
+  aad2605faee2b03f
+    b648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    1939152c1f82c19cc084a681ccdfbd3e;
+  bfb474fd71d891f2
+    4bb65d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9f
+    cdd10d315afef9594ea2d5be06e2e839;
+  c2712a199e533fa9156308cdec3f768281
+    ""
+    ba9d8b182c751b42b9796bae5985d048;
+  e040a9b9a222bd689aef66f5306ceb0c6b
+    08
+    b504bad203181c0281e60284b1e93cd3;
+  ac8b0a22260c571b4a42bb8fdb233bfa6a
+    5cfb0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b5337685a96ed65
+    a23f906ae8ec8b99ff2344d2f22c953c;
+  b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012e4713df46795630e7952d22bb02d
+    e8dc0b7392f193529199018bd6939012;
+}
+
+twofish-ocb3 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7dac5c9941d26
+    ""
+    ""
+    ""
+    7f2677b3ee050809f5e4a511a007024d;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9
+    06
+    ""
+    ""
+    be8deddf16817c9c36d0fd7a1bfbee5e;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794846ecfa14a71
+    ""
+    30
+    c0
+    08ab7139235abe4995e765e6a3cb82a8;
+  c9f137120634c9519848a877ff
+    77bf79192a5b50ade5d9cd
+    ""
+    739a3d1f337f29549e6b0d27a4ba234085406a6136512061f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    47e1cc7b95ebd79869a91c2f062b8f2f577d56908f819cd78f55430e51223e2a5e37bac236601388a2b434c26aa8e7d2
+    5507241b459462d018dae1537cb30e8f;
+  21635c6d62c9269029df3e6057
+    acc87638f508046733d9ff61cd
+    bda3b3e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    21b7f65b000961040ef2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a480
+    7f7357f93fcbabb0d2900992381ab4c3ace2bb992327a4d3d62ff63756b7ef734a0c2a6de3c4b01f76c3531ddd58edcf
+    947dd27aa266be2c3d043571d4a14bb8;
+  30370c33d090c54215abd6b3ad
+    54efc9a38378c5b93bf4f2aad260
+    ""
+    5faee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed54154f8f28523c03d4de1600157846b710ee72807a2219
+    baaa3ba12dcb88379960d13a294e16ae35fc238cca7e1ebd514ef33d2581ffff81c2860478a0ac7be7e2aec8b16ea37fe9e7df6f40
+    b106b18872d92b55b10125092c07ca8a;
+  bfb474fd71d891f24bb65d1563
+    259f9eb53b571ea629c54d57dd2d
+    42f70800df9fcbaca48b77dba189196d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f768281e040
+    a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b6f5fe8368131115c
+    3c67bd32c69ef6446bcf3b1ede303d6bc287368abaa84bbb26ead3899423d3099eca75c966044b67bafb88404ad639fae5857f3a6d
+    fc24dd4b1e6fdad71a59b7595a9e776e;
+  037ba323fe1dc8151784873f
+    0eb5b647da6794c18b5337685a96
+    ""
+    ""
+    ""
+    8b63ff209b6e7a0391301e76a4e0ea39;
+  ed65b9aca338527ef19b09c0
+    63c46f88de9fd41e72d7b97e23e6
+    ea
+    ""
+    ""
+    a433659f0885976882831a3eb89eed53;
+  bdff3bcd211499268878dbf3
+    0f1dad89d4b9b12012e4713df467
+    ""
+    95
+    6d
+    42fe65d65b86c7528a73f89a0ccdf4de;
+  630e7952d22bb02d7100b8b6
+    49377d20a8f083455b663e
+    ""
+    4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f
+    674e1ecd1a10232c74655502be244c4fb08e1f727cb9131f2d2e46de210815b286fc3a75d4e3e1d50c82aa1453b3ca08
+    fa220b12d50ce64f83a4884807d53c83;
+  16e39815d4e9cfce3ed1ecdf
+    3d264a7f16cb16c2e815f422cd
+    f0c8e30308be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a874498ad0abef8bc4f
+    cb70e27e98ef1f0446b42fb144d44b6d00f06dc188d472a784e0c6f21195a3b9f4ae985511265febd11c164720eef9eb
+    8b26c53a06f4ce39b4f35da14098aa964a66b58d9d3385ac71fc9a4f31a6d2c69bd41780ef50785b2d4dc3c8d8de5ec3
+    cb0b3d4ebe62634b66cb4c2f07a22bb8;
+  1c8dd0b00951f284649016ed
+    00456331854bc78bf43966eb0cfa
+    ""
+    9138ddc39908445608fe95e81c2533e31c9c1a9851bc2810d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f
+    45a59590b5218d7503eac38def06f24dde786aee5d74aa5818501d881b5955b3404fc92c02e671c95f03b6e10c875e43309e6314d8
+    cc019326324d5f7a3ccfbf7fb4b4d007;
+  30cbb7f0e4a973a8cd190107
+    314717a77456f3ff669c732b58db
+    8f48af65f7cc9e3fb90e1721b730374ffc9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003cc0c
+    ae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65cc1770a18cbfe6effd1ff6778554acf1270485b203a3c1c4c967c0a4
+    601106b9872e22a419d22e77179a9d3f2f49259f77629473d6fe8cca0c7f80e94230ebb6c59aeaf544a26537b633cf3faca9afaba8
+    3eb85702ecc6a6208ff54e70c555d560;
+  58cb948bdd409b68
+    7fa3a6827b480aa3a4c84cef64f6
+    ""
+    ""
+    ""
+    536ee06e4186eb19069cc7d2611bf1da;
+  c9b53bf8f957f4b0
+    3cf43e89957f9a3e8128f8743d16
+    68
+    ""
+    ""
+    7eb7549c58f0b3e0e900694ad60a34f2;
+  7b7bb8deb9bd205b
+    70e04c091d205cdad9e9a79b1abf
+    ""
+    91
+    a3
+    c223c24ae40f10208b2d07032bf63b9c;
+  b0851e5ca605ac84
+    51399587011677508a15dd
+    ""
+    e524af3e2bee0646541a42c2ecccb44d65bad397abfaf529ee41cf9a05c7efedef3401539c51d2a90bbf7f1bfc338ab0
+    54484aa14a10c80f224295d4fdc98a962cb1a75c388282477149c9e2ad42cb7e19f72d20ecc895ffcdd94e5e184d4195
+    7790694ff014f4f29d8875d3483c665d;
+  ef5746ea8fdcccd2
+    13e33f7e8a5718fd25014107c8
+    e7d715a92add9589d1f5c054b2d983514605ec590294a319b9802068a9f891bc5ba5afabf8c3122d12d7ff3c41122d70
+    d17d4569eaff59a332ba58d5d5589bfe079753ee1a957eb6d6699e6b7ea2725cb2dac07ecde95759ac46fee6dda7abc8
+    873b418fb6d2d8038dd78169b110a57f6e6c58d917f938d27bf4cdb6a9a3e64b6782c71fa8001c22b4025ca054cdc7d4
+    80b7822cbc9921b5249460298edc38b0;
+  ad68daac90cfe22d
+    2f1f2968cc42fa8b669ed3bb3542
+    ""
+    a9cf44bbc8c6254d980398bd94e66eb4563d405e51881e99027b8ab9aea3ccf860b0009740763d96836c5f87b95460938de1288c69
+    0be9726d678b4975083f0553c995e8fe2e9397ae7b1099320daeff9b57e43d306f05d8806cda76754bde21c5aa5a038b2ecd64eff2
+    5fb04d39cbaf88ea62135df4d4661bf0;
+  d80ea12ff4bb5f06
+    9b8a2e86041c1b9fc214e9ca2186
+    ddf1f6a7a3aa7e740da967828e3604b35b15ffaa6c36800d9645563a308ba60076817523bd2abf1261b089
+    d8f23a9c2835076a23faac2cdd67771cc667a8331f0a170b66283e4f834a06148f302c3973accd56f6f24e33958b8c2e2352fd61e4
+    dfbe4cf0fe2983dc101e9daf7d40770c0e6f679e56fe4947602c739ebf22782fb98932e02eb14973d825ea72fb651b6eafca5232ba
+    f92fdadf740caf2c4ea9666b7b052af2;
+  fa8fec816ac861a8b33779f09e7a10fc02
+    a8f48afa3080ee119a52a9a817e4
+    ""
+    ""
+    ""
+    94c3b0151d59ed8a75ce295b97ca07f1;
+  f2b94b0820cab383a8cffeea7c48631579
+    9dc875fba578c8ec4837898a9214
+    2b
+    ""
+    ""
+    c88555532a51ef0d2999fd4b5964866b;
+  5b0677da1ac273117b45bcfff5d5f8b6fd
+    e2893232a9f81d14517ffae475f6
+    ""
+    b9
+    bb
+    2b2e9ebf26398af33b06cae0b1edf872;
+  4a43a67b3d380d2f9aaafe2dd721c0095c
+    8808847689211450ba8095
+    ""
+    ffab1eaadf66fd22ac1976063e113ab61f813e28a1397a7974a1d7f4220c785fe426a5a0e80f678d404147842941feef
+    aa8ff926ae1d31b79b276ba4c6365896a9ac3f2b901cc6edbd98ef230dcb0c1175fc4cda3d3bab4b0cd0761ec60d1bf9
+    679ea4952bdb67410905826ee2164b91;
+  fdc2eb44dc8c0d5e8f444f7f4e0c893959
+    b74dc23a7bb40e7e0013e51506
+    86d2301b43a15a84e81d7f5cedaa49e2414ebf47970e560475cff206877de69146acc3ab6cf8556b7aa776945948d1b8
+    834df2196c92ec1718dcdeee0d52d9539726d2810391b3f9d10c39b07ae8f08ce7cee4758a386a9943e97dedfbe61e73
+    5e3f9325ceafcf8ab3c05194722e13093f75502a722f012fcf67c3f78d905711e90f6f8b2cf11e4911fcf8a988c95fd9
+    715a5d5c308eb6c2d35c87de8c9bc36d;
+  7882cd09c2b9a80f34c0fde11c2481b11f
+    c76bfa4dbf710a9e544e0c536ca1
+    ""
+    e040f9ad5b04140d98edabe08485290a4d87d13b07398a1458c2c6b61dbdbc1cccada8c1a0a9aabb6c4e3c3554f8fb1ef61614c270
+    f0849293c90d1b433a612900ab035a2359b4b0f40dae24c375d721449707bd4fbec89c934fc1610231b4171407dddf5d1cd26e4588
+    e8b6889f97e92f7f90bd3367a6509d3c;
+  295dfc0ca6551ca4bdb75359f91cb9d921
+    056b7de74fc9a9b37154ce6c0b39
+    6179d31f06a1dd5982cbc0d7cb23841da1ae8f4ae480cda98ad6cf2bacf6f9fd3f821330c43f3df6c2b3fa
+    c7cbcf96523d4723f91801325eb8553236651c96788d73d192ee53b3f3ebd66ddd98cedbe88e245de25b1593b70f8601562d90a9b5
+    b1f9684caf6b151fdfcf38fcc9280ba779c2c5845bf3f3778eec5d7157134dd51c762d40ede77e70255f24e7cde7fb41c4e87aef3e
+    ae37ce3b049000e9a941f2e36ffc1b98;
+}
+
+twofish-ocb3-mct {
+  32 e9ce6449d92a77813175926010259b8e;
+  28 a99db77f8c91ea244b94208509e02f0c;
+  24 9a9b6ce8abdbf68c23f2ad13d9e46119;
+  20 c8ef353c81e5742726a0128dd0a0f588;
+  16 9c839aab8a36976e9d320767766e0aa6;
+  12 7f3551b1eb590266c7d59ec6b2b14aa8;
+  10 15fd08dea6427de5fb88050905d313b5;
+   8 3615f256e0edc05af17b680d13534820;
+   4 5a7c50c4e1263d509f2a263ed3587b2d;
+  32 fbe280898f5232dfb0abd143;
+  28 0816b9db96448972f47cc0b0;
+  24 1fdbf8b9482aa91ef2975556;
+  20 3292677aa668b89b179fc183;
+  16 f1f605105a477669efdd0426;
+  12 aa1d9537f7ae2c5c1729c147;
+  10 e9b833d9ff3c9fc07b037282;
+   8 138e0305a1520249dd678e0d;
+   4 ebe50e379a1973275bca0d3d;
+  32 0a09c938c2fa5dba;
+  28 3e38764a044b24fb;
+  24 fe6aa4380d1b161e;
+  20 0e065914f197a226;
+  16 31747d608f91f1a7;
+  12 ffc71de4b3eec92d;
+  10 fbe711df96a56989;
+   8 b38b5c7577aea195;
+   4 9530ea1063f27742;
+}
index be34740..0cea08b 100644 (file)
@@ -68,3 +68,912 @@ xtea {
   c86c21d8c26dc291f662c8f2fe79b74b 0993d3b68c1d4a5d 2b4195c3d67e3f99;
   af4f4615c7c298639b9728251991419f 1e268f9e710313b5 2536ccd8fdfe30e1;
 }
+
+xtea-cmac {
+  60d7bcda163547d348b7551195
+    ""
+    3fe52353f9b144ae;
+  e77022907dd1dff7dac5c9941d
+    26
+    809e38cc35e3a145;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0
+    9e781632642b42cd;
+  a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff
+    8d187ce6f32516ae;
+  77bf79192a5b50
+    ""
+    12bacc0346a97c7f;
+  ade5d9cd739a3d
+    1f
+    76efca6f4ea48f3a;
+  337f29549e6b0d
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f
+    390ba4bcc9d100f3;
+  2dd88374d8cde8
+    e160ad10997a21635c6d62c9269029df3e6057
+    666111e472d8cdfd;
+  acc87638f508046733d9
+    ""
+    2b1ff3b380aa5d5a;
+  ff61cdbda3b3e9878731
+    eb
+    85351b61c26c94cf;
+  fedd4705e505da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    d8a892f0975b7e2c;
+  966f27043eb621b7f65b
+    000961040ef2f9b2fc5fa450727a9b542cde52
+    85b42005a520b9fc;
+  ebfda19d0ccc520f21
+    ""
+    cf0f227f8b2a8b46;
+  5eb57bb3a4f3ebbbb1
+    8a
+    a0cdc4acc3d77c92;
+  c6c95a97a48030370c
+    33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    ac879bd822cf405d;
+  5faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b9458630
+    295b9c45cd0a8bab;
+}
+
+xtea-ccm {
+  60d7bcda163547d348b7551195
+    e77022
+    ""
+    ""
+    ""
+    254c9820;
+  907dd1dff7dac5c9941d26d0c6
+    eb14ad
+    56
+    ""
+    ""
+    628ee141;
+  8f86edd1dc9268eeee533285a6
+    ed810c
+    ""
+    9b
+    b6
+    c68f9ba1;
+  689daaa9060d2d4b6003062365
+    b0a54364c7
+    6c160f11896c4794846ecfa14a7130c9f137120634c95198
+    48a877ff77bf79192a5b50ade5d9cd739a3d1f337f29549e
+    5d451b7841e1046387c69f33e87585eedf30cd7df2d4a409
+    ae1ade48fb30df53;
+  6b0d27a4ba234085406a613651
+    2061f7080c
+    c07df0591d8fa21f2dd88374d8cde8e160ad10
+    997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbd
+    587e64a45665ec8f4b0561f911c55bbddc89d3cb923ee2a79736d853f2
+    5dc68eee0336d9df;
+  a3b3e9878731eb
+    fedd47
+    ""
+    ""
+    ""
+    e731a2e4;
+  05e505da1435dc
+    eaa7b1
+    cc
+    ""
+    ""
+    d61b3844;
+  49ae1d50c38201
+    a89447
+    ""
+    6b
+    65
+    ae5cf49a;
+  3f102b752eb952
+    9533966f27
+    043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a
+    5cda052e11d440e05347a5d392610573bb3382f451a23c91
+    6b984d2bbcde1308;
+  97a48030370c33
+    d090c54215
+    abd6b3ad54efc9a38378c5b93bf4f2aad2605f
+    aee2b03fb648e27fff63102758fe2b69ac26afa3349829b94586306fed
+    e50f8051933dfcda7693161d2fa0885f455a610c3178d245abb8a7869c
+    9bba96ded767f109;
+  54154f8f28523c03d4de
+    160015
+    ""
+    ""
+    ""
+    06d07295;
+  7846b710ee72807a2219
+    bfb474
+    fd
+    ""
+    ""
+    613f97d3;
+  71d891f24bb65d156325
+    9f9eb5
+    ""
+    3b
+    10
+    5262f065;
+  571ea629c54d57dd2d42
+    f70800df9f
+    cbaca48b77dba189196d1ebba10b0467cb9fc2712a199e53
+    3fa9156308cdec3f768281e040a9b9a222bd689aef66f530
+    728d0e2c1f92403c6c91538ca0a4d33c644728aa324d6fec
+    3c8af92993cf2dfc;
+  6ceb0c6b08ac8b0a2226
+    0c571b4a42
+    bb8fdb233bfa6a5cfb0bad7d95214ade49cb3b
+    6f5fe8368131115c037ba323fe1dc8151784873f0eb5b647da6794c18b
+    758c2450b1b4b633088e2dacece8fce73bb681518bc74f24427f9cf532
+    768cfa0b76676f6e;
+  5337685a96ed65b9ac
+    a33852
+    ""
+    ""
+    ""
+    cd3b5fbe;
+  7ef19b09c063c46f88
+    de9fd4
+    1e
+    ""
+    ""
+    77ec39fe;
+  72d7b97e23e6eabdff
+    3bcd21
+    ""
+    14
+    2b
+    12bba0f1;
+  99268878dbf30f1dad
+    89d4b9b120
+    12e4713df46795630e7952d22bb02d7100b8b649377d20a8
+    f083455b663e4ee1315f3c8f2aebfa921451dcd1af5813b7
+    84148214729971a1616f5a0a2261662e90ffe6ee853fc892
+    cd1f0f55d1d79d35;
+  0d30ce2f1fef6ef315
+    d079839180
+    5da08da3aefc5f8584b7c5e617669c0f16e398
+    15d4e9cfce3ed1ecdf3d264a7f16cb16c2e815f422cdf0c8e30308be3c
+    fc533246fa0f63332c3806595c6a35a6cd0499e973ae7a0055755b4026
+    ff6e5bc754f0adfd;
+}
+
+xtea-eax {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    5f1c8be04844ffdf;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    3fec55f722a3295e;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    41b22cdc7a09818c;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    68
+    8b0dec6244e10dd9;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794
+    846ecfa14a7130c9f137120634c9519848a877ff77bf7919
+    2a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    4c3b648b0d6a0bf20eb496a17201e4fdd7581e1d34fe19f5
+    9576894304df1c06;
+  406a6136512061f7080cc07df0
+    591d8fa21f2dd8
+    8374d8cde8e160ad10997a21635c6d62c92690
+    29df3e6057acc87638f508046733d9ff61cdbda3b3e9878731ebfedd47
+    495ac874eee71cda95fc4133cd8080514898385e542f44f56734ff86cf
+    88db0b0c36963625;
+  05e505da1435dc
+    ""
+    ""
+    ""
+    ""
+    b8d2cf3b4a2c82ed;
+  eaa7b1cc49ae1d
+    50
+    ""
+    ""
+    ""
+    ff304d08904cc45b;
+  c38201a894476b
+    ""
+    3f
+    ""
+    ""
+    f13209350bfea66c;
+  102b752eb95295
+    ""
+    ""
+    33
+    78
+    468ff217fd2da0e0;
+  966f27043eb621
+    b7f65b000961040e
+    f2f9b2fc5fa450727a9b542cde52ebfda19d0ccc520f215e
+    b57bb3a4f3ebbbb18ac6c95a97a48030370c33d090c54215
+    c78a890e811a86978a2b944c7741ce0fc415aba17675e5be
+    835bb97626f8a99e;
+  abd6b3ad54efc9
+    a38378c5b93bf4
+    f2aad2605faee2b03fb648e27fff63102758fe
+    2b69ac26afa3349829b94586306fed54154f8f28523c03d4de16001578
+    f8331f39c783a39406102bfdc1b324d0d4dabe5ec886474caef97209fd
+    e59ad9e764305aa4;
+  46b710ee72807a2219bf
+    ""
+    ""
+    ""
+    ""
+    603bc1df6ad3c9ef;
+  b474fd71d891f24bb65d
+    15
+    ""
+    ""
+    ""
+    bd337ef6bfba87bb;
+  63259f9eb53b571ea629
+    ""
+    c5
+    ""
+    ""
+    155833e773266034;
+  4d57dd2d42f70800df9f
+    ""
+    ""
+    cb
+    43
+    d77a671a2285a75a;
+  aca48b77dba189196d1e
+    bba10b0467cb9fc2
+    712a199e533fa9156308cdec3f768281e040a9b9a222bd68
+    9aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb23
+    ba08278e81846ceb38153d309a3a01a57f415763091e31cd
+    9ec9746c66fea592;
+  3bfa6a5cfb0bad7d9521
+    4ade49cb3b6f5f
+    e8368131115c037ba323fe1dc8151784873f0e
+    b5b647da6794c18b5337685a96ed65b9aca338527ef19b09c063c46f88
+    b73f49154f95bdba7d27565233290a8b987df10315aa519dd927f2c862
+    8ebd3aa28ee4a127;
+  de9fd41e72d7b97e23
+    ""
+    ""
+    ""
+    ""
+    6139eca5fd2a9750;
+  e6eabdff3bcd211499
+    26
+    ""
+    ""
+    ""
+    8acc9b1625d62fb2;
+  8878dbf30f1dad89d4
+    ""
+    b9
+    ""
+    ""
+    9730f31424a77b48;
+  b12012e4713df46795
+    ""
+    ""
+    63
+    33
+    0db62109955eeea5;
+  0e7952d22bb02d7100
+    b8b649377d20a8f0
+    83455b663e4ee1315f3c8f2aebfa921451dcd1af5813b70d
+    30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5
+    67acf23790a2997df84bf037c61118541471b963e076eb73
+    b9d46f9d24d74df0;
+  e617669c0f16e39815
+    d4e9cfce3ed1ec
+    df3d264a7f16cb16c2e815f422cdf0c8e30308
+    be3c31e6bc58c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed1
+    913b6bc765751a1b774bdd80b81b54a40e6b943acb8d922c5ea0b049d3
+    32a223a2cb999dba;
+}
+
+xtea-gcm {
+  60d7bcda163547d348b7551195
+    ""
+    ""
+    ""
+    ""
+    965c89c5e9e67150;
+  e77022907dd1dff7dac5c9941d
+    26
+    ""
+    ""
+    ""
+    4bc1d47c6aa62964;
+  d0c6eb14ad568f86edd1dc9268
+    ""
+    ee
+    ""
+    ""
+    efbae174fcba078d;
+  ee533285a6ed810c9b689daaa9
+    ""
+    ""
+    06
+    e8
+    3c4fa10c897f0762;
+  0d2d4b6003062365b0a54364c7
+    6c160f11896c4794
+    846ecfa14a7130c9f137120634c9519848a877ff77bf7919
+    2a5b50ade5d9cd739a3d1f337f29549e6b0d27a4ba234085
+    bffee89ad704bd37259e148b3c038bf2ee483ee7e15cddd8
+    f679257dc029e7f1;
+  406a6136512061f7080cc07df0
+    591d8fa2
+    1f2dd88374d8cde8e160ad
+    10997a21635c6d62c9269029df3e6057acc87638f508046733d9ff61cdbda3b3e9
+    77f4d28e0589a98ab60a4c53cf2a34a4212aee7756a9ebf17f5c52b982ae5dc249
+    d61642f2623b785f;
+  878731ebfedd4705e505da1435
+    dceaa7b1cc49ae
+    1d50c38201a894476b3f102b752eb952953396
+    6f27043eb621b7f65b000961040ef2f9b2fc5fa450727a9b542cde52eb
+    f9d9ebb1b908d8d19893ce0bebb4c2b87110adc572425cf0d88b32fe2c
+    aa3002dffd42e3ff;
+  fda19d0ccc520f
+    ""
+    ""
+    ""
+    ""
+    dbafe92d502b3295;
+  215eb57bb3a4f3
+    eb
+    ""
+    ""
+    ""
+    09ac92680bc52ddf;
+  bbb18ac6c95a97
+    ""
+    a4
+    ""
+    ""
+    2845ab8e15cc6e83;
+  8030370c33d090
+    ""
+    ""
+    c5
+    3e
+    8b12bd215589da19;
+  4215abd6b3ad54
+    efc9a38378c5b93b
+    f4f2aad2605faee2b03fb648e27fff63102758fe2b69ac26
+    afa3349829b94586306fed54154f8f28523c03d4de160015
+    3dd971d21e1f273a18a156a12cc084d265744982a0bc84ee
+    e4bc1c22d869ce1f;
+  7846b710ee7280
+    7a2219bf
+    b474fd71d891f24bb65d15
+    63259f9eb53b571ea629c54d57dd2d42f70800df9fcbaca48b77dba189196d1ebb
+    35afbe16c12e4a71ee59d1e03479d82c240119d25d7f759298ca0c6a7261ec0df7
+    0e3afa58d945282f;
+  a10b0467cb9fc2
+    712a199e533fa9
+    156308cdec3f768281e040a9b9a222bd689aef
+    66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb233bfa6a5cfb0bad
+    91c7d3e6bdfdc99a009642e8586acdb300caf64ccfa844f823b02fb3a3
+    9d1d569032d47694;
+  7d95214ade49cb3b6f5f
+    ""
+    ""
+    ""
+    ""
+    bf7b041a488d393e;
+  e8368131115c037ba323
+    fe
+    ""
+    ""
+    ""
+    41f54145c986899b;
+  1dc8151784873f0eb5b6
+    ""
+    47
+    ""
+    ""
+    46aa574328fd728c;
+  da6794c18b5337685a96
+    ""
+    ""
+    ed
+    fb
+    b2ae7fdba380ced8;
+  65b9aca338527ef19b09
+    c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89
+    d4b9b12012e4713df46795630e7952d22bb02d7100b8b649
+    9b3dd3969b6367d11a17e2c10241592ea531ecf0445749eb
+    ee022fa7e8e3a576;
+  377d20a8f083455b663e
+    4ee1315f
+    3c8f2aebfa921451dcd1af
+    5813b70d30ce2f1fef6ef315d0798391805da08da3aefc5f8584b7c5e617669c0f
+    4d32b3228edff4d5a35588331c433defeca851b5843150082ac23d5607ea06c83e
+    d1458ac231a4ac20;
+  16e39815d4e9cfce3ed1
+    ecdf3d264a7f16
+    cb16c2e815f422cdf0c8e30308be3c31e6bc58
+    c0b7cadcb658b970e47479a684b5aefa69a4cd52147ed12ca986981a87
+    8603545fa254880d1fceb81d2e937217d0edfd7f6713078624772c0f40
+    fdc8cb8bc51a1533;
+  4498ad0abef8bc4fcb
+    ""
+    ""
+    ""
+    ""
+    9c3e0d53b5dca992;
+  70e27e98ef1f0446b4
+    2f
+    ""
+    ""
+    ""
+    04bf8339880c70bd;
+  b144d44b6d00f06dc1
+    ""
+    88
+    ""
+    ""
+    fefa3ef4a95dbe20;
+  d472a784e0c6f21195
+    ""
+    ""
+    a3
+    6c
+    05da912be7dd7846;
+  b9f4ae985511265feb
+    d11c164720eef9eb
+    1c8dd0b00951f284649016ed00456331854bc78bf43966eb
+    0cfa9138ddc39908445608fe95e81c2533e31c9c1a9851bc
+    e72acc6e0d4490e549b969d30f773905cd6dc77f4ce77b22
+    bb74ac6f9139c65f;
+  2810d858cbbc8424d1
+    26b807e6
+    daa089c3f9099c5ffb8241
+    73d7634c04226f30cbb7f0e4a973a8cd190107314717a77456f3ff669c732b58db
+    9e8854454d108c12f18f23fb9a251b52e734a3221aea99928614d209d6e57a4305
+    44d67f8883a717e5;
+  8f48af65f7cc9e3fb9
+    0e1721b730374f
+    fc9bc597f56ccbb2f294b38766fc69f6a9f2c0
+    945ffd505003cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f09
+    ae7ea2a80ef6b2ec3b48f32be277ce5f984f50af216261f69bc2e65c2c
+    db4d7130d6508aa8;
+}
+
+xtea-ocb1 {
+  60d7bcda163547d348b7551195
+    e77022907dd1dff7
+    ""
+    ""
+    ""
+    07bef2af9ee05be5;
+  dac5c9941d26d0c6eb14ad568f
+    86edd1dc9268eeee
+    53
+    ""
+    ""
+    f772f8da875c6c16;
+  3285a6ed810c9b689daaa9060d
+    2d4b6003062365b0
+    ""
+    a5
+    09
+    ae03c614cee35738;
+  4364c76c160f11896c4794846e
+    cfa14a7130c9f137
+    ""
+    120634c9519848a877ff77bf79192a5b50ade5d9cd739a3d
+    667c317875cb68a2df759151a2340d3b90c7652e0a4cfcb1
+    93e92f0eef1160fb;
+  1f337f29549e6b0d27a4ba2340
+    85406a6136512061
+    f7080cc07df0591d8fa21f2dd88374d8cde8e160ad10997a
+    21635c6d62c9269029df3e6057acc87638f508046733d9ff
+    6f5d6a11b04cb03f734de83608675ca8cbb718197d5e6dae
+    e69dd7ec56052187;
+  61cdbda3b3e9878731ebfedd47
+    05e505da1435dcea
+    ""
+    a7b1cc49ae1d50c38201a894476b3f102b752eb9529533966f27043eb6
+    b2404d623b8994262e27a6e4e735dee18349a90f530e2a3f636d7c5f71
+    ef92c0c42a1911fb;
+  21b7f65b000961040ef2f9b2fc
+    5fa450727a9b542c
+    de52ebfda19d0ccc520f215eb57bb3a4f3ebbb
+    b18ac6c95a97a48030370c33d090c54215abd6b3ad54efc9a38378c5b9
+    b3c350ff78424273c10f103bbda2de658e037d6a35632be78052c55b53
+    131383b16016457a;
+  3bf4f2aad2605f
+    aee2b03fb648e27f
+    ""
+    ""
+    ""
+    7080c42bba62492f;
+  ff63102758fe2b
+    69ac26afa3349829
+    b9
+    ""
+    ""
+    a4e5b67ccd313289;
+  4586306fed5415
+    4f8f28523c03d4de
+    ""
+    16
+    00
+    d86ee5c4829dba67;
+  00157846b710ee
+    72807a2219bfb474
+    ""
+    fd71d891f24bb65d1563259f9eb53b571ea629c54d57dd2d
+    5a963f2a946fc9b06c9c9949f50eb85c1f3b54e009ea3950
+    43d5535e5b6fc923;
+  42f70800df9fcb
+    aca48b77dba18919
+    6d1ebba10b0467cb9fc2712a199e533fa9156308cdec3f76
+    8281e040a9b9a222bd689aef66f5306ceb0c6b08ac8b0a22
+    fc5846409e369e01687535ae0373827734da2375afab9ad3
+    fb2bf11df41a072f;
+  260c571b4a42bb
+    8fdb233bfa6a5cfb
+    ""
+    0bad7d95214ade49cb3b6f5fe8368131115c037ba323fe1dc815178487
+    b7abf514a519880bcf9a1dd906236193181274945f26eeea26de9a4480
+    0a4c5b3dea189c9f;
+  3f0eb5b647da67
+    94c18b5337685a96
+    ed65b9aca338527ef19b09c063c46f88de9fd4
+    1e72d7b97e23e6eabdff3bcd211499268878dbf30f1dad89d4b9b12012
+    abb5a85ee34c20c9ac26d5b84fb2079b949508c3a6c248aef713c7e3c8
+    66f1833b4afd2bd8;
+  e4713df46795630e7952
+    d22bb02d7100b8b6
+    ""
+    ""
+    ""
+    be24074b27f49059;
+  49377d20a8f083455b66
+    3e4ee1315f3c8f2a
+    eb
+    ""
+    ""
+    ee190cc6ecad475c;
+  fa921451dcd1af5813b7
+    0d30ce2f1fef6ef3
+    ""
+    15
+    bb
+    5a83e24c3f3d84e9;
+  d0798391805da08da3ae
+    fc5f8584b7c5e617
+    ""
+    669c0f16e39815d4e9cfce3ed1ecdf3d264a7f16cb16c2e8
+    a573de0fdef866acaa2ebd0be9a101af7f8e4ce6d9f33a2a
+    f3acd5608b4d8863;
+  15f422cdf0c8e30308be
+    3c31e6bc58c0b7ca
+    dcb658b970e47479a684b5aefa69a4cd52147ed12ca98698
+    1a874498ad0abef8bc4fcb70e27e98ef1f0446b42fb144d4
+    acb6678d5dcfe7373c937b1b743ac60d7b039ee405cc184d
+    426f814ef7af424d;
+  4b6d00f06dc188d472a7
+    84e0c6f21195a3b9
+    ""
+    f4ae985511265febd11c164720eef9eb1c8dd0b00951f284649016ed00
+    6b9981f8864012346d4faa801dc7d0aa35703d3a19fcbfd65c79509cc1
+    4b2c765518bd12b4;
+  456331854bc78bf43966
+    eb0cfa9138ddc399
+    08445608fe95e81c2533e31c9c1a9851bc2810
+    d858cbbc8424d126b807e6daa089c3f9099c5ffb824173d7634c04226f
+    ade2fa7115805e2fe9464340d7b5a7c97c093ded512f5c7cec815ff278
+    af6dddac99d6a024;
+  30cbb7f0e4a973a8cd
+    190107314717a774
+    ""
+    ""
+    ""
+    1bf75ebfe2f2c874;
+  56f3ff669c732b58db
+    8f48af65f7cc9e3f
+    b9
+    ""
+    ""
+    b5e6cebf8f565eb4;
+  0e1721b730374ffc9b
+    c597f56ccbb2f294
+    ""
+    b3
+    18
+    feee3b50ee01bc04;
+  8766fc69f6a9f2c094
+    5ffd505003cc0cae
+    ""
+    9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911e32d65
+    e918a45ec5088f385ab211351a06495693bfb81dcd0d7749
+    9a6e716945055b00;
+  cc1770a18cbfe6effd
+    1ff6778554acf127
+    0485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b
+    480aa3a4c84cef64f6c9b53bf8f957f4b03cf43e89957f9a
+    b25ea7ed37027181c51ab3d374c9f2cf8dc6a5c275c93b11
+    6b72bcad7a2cc4a4;
+  3e8128f8743d16687b
+    7bb8deb9bd205b70
+    ""
+    e04c091d205cdad9e9a79b1abf91b0851e5ca605ac8451399587011677
+    45c3c8686b2cd92247a8afc0ca13a832de78417abbd11d3e7a687bc4cc
+    6247cc4284c11080;
+  508a15dde524af3e2b
+    ee0646541a42c2ec
+    ccb44d65bad397abfaf529ee41cf9a05c7efed
+    ef3401539c51d2a90bbf7f1bfc338ab0ef5746ea8fdcccd213e33f7e8a
+    be2975c04e206859c47b5380c0e22d177563ce76c47538d89ae0be19f9
+    9cc636850cbc148f;
+}
+
+xtea-pmac1 {
+  60d7bcda163547d348b7551195
+    ""
+    5afaac6a8b1d8747;
+  e77022907dd1dff7dac5c9941d
+    26
+    586ad5dfb39d35c5;
+  d0c6eb14ad568f86edd1dc9268
+    eeee533285a6ed810c9b689daaa9060d2d4b6003062365b0
+    e6a7ee16109f3b0d;
+  a54364c76c160f11896c479484
+    6ecfa14a7130c9f137120634c9519848a877ff
+    320631d3f31f8840;
+  77bf79192a5b50
+    ""
+    eeb3c7cb0d072322;
+  ade5d9cd739a3d
+    1f
+    377efb6339f47074;
+  337f29549e6b0d
+    27a4ba234085406a6136512061f7080cc07df0591d8fa21f
+    23266ff9052777ea;
+  2dd88374d8cde8
+    e160ad10997a21635c6d62c9269029df3e6057
+    387edca755c71aa8;
+  acc87638f508046733d9
+    ""
+    f88c2d9748aafff6;
+  ff61cdbda3b3e9878731
+    eb
+    5502443fc2d9e373;
+  fedd4705e505da1435dc
+    eaa7b1cc49ae1d50c38201a894476b3f102b752eb9529533
+    722b4728cbe72195;
+  966f27043eb621b7f65b
+    000961040ef2f9b2fc5fa450727a9b542cde52
+    c4d4788b5aaaba15;
+  ebfda19d0ccc520f21
+    ""
+    df7b7666d395d55c;
+  5eb57bb3a4f3ebbbb1
+    8a
+    28c63dbfb924352f;
+  c6c95a97a48030370c
+    33d090c54215abd6b3ad54efc9a38378c5b93bf4f2aad260
+    df15e66620945a9d;
+  5faee2b03fb648e27f
+    ff63102758fe2b69ac26afa3349829b9458630
+    5017699c228b645c;
+}
+
+xtea-ocb3 {
+  60d7bcda163547d348b7551195
+    e77022907dd1
+    ""
+    ""
+    ""
+    5d2c01e9160963e2;
+  dff7dac5c9941d26d0c6eb14ad
+    568f86edd1dc
+    92
+    ""
+    ""
+    f4290b5fa1095a3b;
+  68eeee533285a6ed810c9b689d
+    aaa9060d2d4b
+    ""
+    60
+    86
+    a0258d79cfe3419c;
+  03062365b0a54364c76c160f11
+    896c47
+    ""
+    94846ecfa14a7130c9f137120634c9519848a877ff77bf79
+    6610c7e7e150973b3af3229eaca70189ec0e13b564297b84
+    235c7f65cfd0cda9;
+  192a5b50ade5d9cd739a3d1f33
+    7f29549e6b
+    0d27a4ba234085406a6136512061f7080cc07df0591d8fa2
+    1f2dd88374d8cde8e160ad10997a21635c6d62c9269029df
+    ea5f7d5a908f059911b6b766f706d5f3c9a1b7d5b4d42065
+    ba47585a0fa5b8d2;
+  3e6057acc87638f508046733d9
+    ff61cdbda3b3
+    ""
+    e9878731ebfedd4705e505da1435dceaa7b1cc49ae1d50c38201a89447
+    1eb152c297208c394377db7669f0147c95b8fac5b1b8607d9584253b23
+    d9340baabda4544b;
+  6b3f102b752eb9529533966f27
+    043eb621b7f6
+    5b000961040ef2f9b2fc5fa450727a9b542cde
+    52ebfda19d0ccc520f215eb57bb3a4f3ebbbb18ac6c95a97a48030370c
+    67480201e5ad84d5c418b97dd662d14467346d3a41358000bcd2f70ad4
+    c401dcec1ed2f580;
+  33d090c54215ab
+    d6b3ad54efc9
+    ""
+    ""
+    ""
+    55b5295ceea5a2b0;
+  a38378c5b93bf4
+    f2aad2605fae
+    e2
+    ""
+    ""
+    0f315886523d1ef8;
+  b03fb648e27fff
+    63102758fe2b
+    ""
+    69
+    f9
+    6363d821109640b7;
+  ac26afa3349829
+    b94586
+    ""
+    306fed54154f8f28523c03d4de1600157846b710ee72807a
+    5d059d165b480d0bd30aa01fbc99b6c73bb78a97846f94e0
+    dd5e7c83be0625ef;
+  2219bfb474fd71
+    d891f24bb6
+    5d1563259f9eb53b571ea629c54d57dd2d42f70800df9fcb
+    aca48b77dba189196d1ebba10b0467cb9fc2712a199e533f
+    02ba51adcc2bb6ba3ab41756291366f14f0cb20893fa39a9
+    2b280bddba65b2fa;
+  a9156308cdec3f
+    768281e040a9
+    ""
+    b9a222bd689aef66f5306ceb0c6b08ac8b0a22260c571b4a42bb8fdb23
+    cb82582817fa2dd3563bbc12c501093140d5df1fdbd0a319ad4f28cb28
+    0da5ea5b1a5fdddd;
+  3bfa6a5cfb0bad
+    7d95214ade49
+    cb3b6f5fe8368131115c037ba323fe1dc81517
+    84873f0eb5b647da6794c18b5337685a96ed65b9aca338527ef19b09c0
+    2da5aa1294ef89aacc993ebd46ebec94a3feac279d392c27d92b0dbd30
+    f2713c40cf993ef3;
+  63c46f88de9fd41e72d7
+    b97e23e6eabd
+    ""
+    ""
+    ""
+    f3501e0fcf27dbb5;
+  ff3bcd211499268878db
+    f30f1dad89d4
+    b9
+    ""
+    ""
+    87b3dbbf4f9cc61d;
+  b12012e4713df4679563
+    0e7952d22bb0
+    ""
+    2d
+    c0
+    5618eb373dd8374f;
+  7100b8b649377d20a8f0
+    83455b
+    ""
+    663e4ee1315f3c8f2aebfa921451dcd1af5813b70d30ce2f
+    99096150a0fe314a00a2336f097ad0f885f03c0b7cccd127
+    a66de7481d491c0c;
+  1fef6ef315d079839180
+    5da08da3ae
+    fc5f8584b7c5e617669c0f16e39815d4e9cfce3ed1ecdf3d
+    264a7f16cb16c2e815f422cdf0c8e30308be3c31e6bc58c0
+    3a678d2a777b2eaa8d344e42aedd5e722ffef69ba742ae1a
+    d6bc78818c3bb4a3;
+  b7cadcb658b970e47479
+    a684b5aefa69
+    ""
+    a4cd52147ed12ca986981a874498ad0abef8bc4fcb70e27e98ef1f0446
+    85540182992781ca0104d764814e47ede859164af3405567d0c98bc7a0
+    8857121b533f8a6b;
+  b42fb144d44b6d00f06d
+    c188d472a784
+    e0c6f21195a3b9f4ae985511265febd11c1647
+    20eef9eb1c8dd0b00951f284649016ed00456331854bc78bf43966eb0c
+    8e650a51a481be8fa4eb4277832e68fef19321017bfcb05543ccbd1278
+    b58014483ea856ce;
+  fa9138ddc399084456
+    08fe95e81c25
+    ""
+    ""
+    ""
+    d6f325e74486f817;
+  33e31c9c1a9851bc28
+    10d858cbbc84
+    24
+    ""
+    ""
+    1b88f76f4bff9de0;
+  d126b807e6daa089c3
+    f9099c5ffb82
+    ""
+    41
+    8e
+    1f85ea188d2fbe58;
+  73d7634c04226f30cb
+    b7f0e4
+    ""
+    a973a8cd190107314717a77456f3ff669c732b58db8f48af
+    8ac6753b0a1edc91a058b5bd8cd84f6e2d84a066d3263392
+    ea000b35774b2c35;
+  65f7cc9e3fb90e1721
+    b730374ffc
+    9bc597f56ccbb2f294b38766fc69f6a9f2c0945ffd505003
+    cc0cae9ce021a5f1fa4ffa91544485f1a1258b2b9b8f0911
+    96bdfd04ff0191407c3b1d881eb29c718dbfc93ef7852b24
+    3b4e8b97f9c055ea;
+  e32d65cc1770a18cbf
+    e6effd1ff677
+    ""
+    8554acf1270485b203a3c1c4c967c0a458cb948bdd409b687fa3a6827b
+    99ab24f8a320e106aa12864be588d6af0459d33e27a7b0ab9dcad9de9d
+    f740e2e18cae5773;
+  480aa3a4c84cef64f6
+    c9b53bf8f957
+    f4b03cf43e89957f9a3e8128f8743d16687b7b
+    b8deb9bd205b70e04c091d205cdad9e9a79b1abf91b0851e5ca605ac84
+    8d22fd98971cd873b0fab7bd557d5c4076eca3ed5f5acf7fa656bcc0b2
+    16899233ed9068ed;
+}
+
+xtea-ocb3-mct {
+  16 8cf53d7d6b43cdf1;
+  14 5583f3a52de141d8;
+  12 0b6565df07a02f3c;
+  10 39da0a29f89a2699;
+   8 24ea4af6cf4b09f8;
+   6 6b4a51ac943cfa79;
+   4 1f1b844caf0ddbae;
+  16 6c4482111229;
+  14 117519ba3a0f;
+  12 ceb3bd9e235c;
+  10 4d6a4907b3b5;
+   8 6f7224393f2c;
+   6 4629c2df66b4;
+   4 c0ce4bd2a198;
+  16 9ce1b811;
+  14 b50aeacb;
+  12 7c8e696b;
+  10 8a6a0f17;
+   8 f0422ae8;
+   6 1c8cb415;
+   4 b31dc24a;
+}
diff --git a/utils/advmodes b/utils/advmodes
new file mode 100755 (executable)
index 0000000..834771c
--- /dev/null
@@ -0,0 +1,1033 @@
+#! /usr/bin/python
+
+from sys import argv, exit
+from struct import unpack, pack
+from itertools import izip
+import catacomb as C
+
+R = C.FibRand(0)
+
+###--------------------------------------------------------------------------
+### Utilities.
+
+def combs(things, k):
+  ii = range(k)
+  n = len(things)
+  while True:
+    yield [things[i] for i in ii]
+    for j in xrange(k):
+      if j == k - 1: lim = n
+      else: lim = ii[j + 1]
+      i = ii[j] + 1
+      if i < lim:
+        ii[j] = i
+        break
+      ii[j] = j
+    else:
+      return
+
+POLYMAP = {}
+
+def poly(nbits):
+  try: return POLYMAP[nbits]
+  except KeyError: pass
+  base = C.GF(0).setbit(nbits).setbit(0)
+  for k in xrange(1, nbits, 2):
+    for cc in combs(range(1, nbits), k):
+      p = base + sum(C.GF(0).setbit(c) for c in cc)
+      if p.irreduciblep(): POLYMAP[nbits] = p; return p
+  raise ValueError, nbits
+
+def prim(nbits):
+  ## No fancy way to do this: I'd need a much cleverer factoring algorithm
+  ## than I have in my pockets.
+  if nbits == 64: cc = [64, 4, 3, 1, 0]
+  elif nbits == 96: cc = [96, 10, 9, 6, 0]
+  elif nbits == 128: cc = [128, 7, 2, 1, 0]
+  elif nbits == 192: cc = [192, 15, 11, 5, 0]
+  elif nbits == 256: cc = [256, 10, 5, 2, 0]
+  else: raise ValueError, 'no field for %d bits' % nbits
+  p = C.GF(0)
+  for c in cc: p = p.setbit(c)
+  return p
+
+def Z(n):
+  return C.ByteString.zero(n)
+
+def mul_blk_gf(m, x, p): return ((C.GF.loadb(m)*x)%p).storeb((p.nbits + 6)/8)
+
+def with_lastp(it):
+  it = iter(it)
+  try: j = next(it)
+  except StopIteration: raise ValueError, 'empty iter'
+  lastp = False
+  while not lastp:
+    i = j
+    try: j = next(it)
+    except StopIteration: lastp = True
+    yield i, lastp
+
+def safehex(x):
+  if len(x): return hex(x)
+  else: return '""'
+
+def keylens(ksz):
+  sel = []
+  if isinstance(ksz, C.KeySZSet): kk = ksz.set
+  elif isinstance(ksz, C.KeySZRange): kk = range(ksz.min, ksz.max, ksz.mod)
+  elif isinstance(ksz, C.KeySZAny): kk = range(64); sel = [0]
+  kk = list(kk); kk = kk[:]
+  n = len(kk)
+  while n and len(sel) < 4:
+    i = R.range(n)
+    n -= 1
+    kk[i], kk[n] = kk[n], kk[i]
+    sel.append(kk[n])
+  return sel
+
+def pad0star(m, w):
+  n = len(m)
+  if not n: r = w
+  else: r = (-len(m))%w
+  if r: m += Z(r)
+  return C.ByteString(m)
+
+def pad10star(m, w):
+  r = w - len(m)%w
+  if r: m += '\x80' + Z(r - 1)
+  return C.ByteString(m)
+
+def ntz(i):
+  j = 0
+  while (i&1) == 0: i >>= 1; j += 1
+  return j
+
+def blocks(x, w):
+  v, i, n = [], 0, len(x)
+  while n - i > w:
+    v.append(C.ByteString(x[i:i + w]))
+    i += w
+  return v, C.ByteString(x[i:])
+
+EMPTY = C.bytes('')
+
+def blocks0(x, w):
+  v, tl = blocks(x, w)
+  if len(tl) == w: v.append(tl); tl = EMPTY
+  return v, tl
+
+def dummygen(bc): return []
+
+CUSTOM = {}
+
+###--------------------------------------------------------------------------
+### RC6.
+
+class RC6Cipher (type):
+  def __new__(cls, w, r):
+    name = 'rc6-%d/%d' % (w, r)
+    me = type(name, (RC6Base,), {})
+    me.name = name
+    me.r = r
+    me.w = w
+    me.blksz = w/2
+    me.keysz = C.KeySZRange(me.blksz, 1, 255, 1)
+    return me
+
+def rotw(w):
+  return w.bit_length() - 1
+
+def rol(w, x, n):
+  m0, m1 = C.MP(0).setbit(w - n) - 1, C.MP(0).setbit(n) - 1
+  return ((x&m0) << n) | (x >> (w - n))&m1
+
+def ror(w, x, n):
+  m0, m1 = C.MP(0).setbit(n) - 1, C.MP(0).setbit(w - n) - 1
+  return ((x&m0) << (w - n)) | (x >> n)&m1
+
+class RC6Base (object):
+
+  ## Magic constants.
+  P400 = C.MP(0xb7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfef324e7738926cfbe5f4bf8d8d8c31d763da06)
+  Q400 = C.MP(0x9e3779b97f4a7c15f39cc0605cedc8341082276bf3a27251f86c6a11d0c18e952767f0b153d27b7f0347045b5bf1827f0188)
+
+  def __init__(me, k):
+
+    ## Build the magic numbers.
+    P = me.P400 >> (400 - me.w)
+    if P%2 == 0: P += 1
+    Q = me.Q400 >> (400 - me.w)
+    if Q%2 == 0: Q += 1
+    M = C.MP(0).setbit(me.w) - 1
+
+    ## Convert the key into words.
+    wb = me.w/8
+    c = (len(k) + wb - 1)/wb
+    kb, ktl = blocks(k, me.w/8)
+    L = map(C.MP.loadl, kb + [ktl])
+    assert c == len(L)
+
+    ## Build the subkey table.
+    me.d = rotw(me.w)
+    n = 2*me.r + 4
+    S = [(P + i*Q)&M for i in xrange(n)]
+
+    ##for j in xrange(c):
+    ##  print 'L[%3d] = %s' % (j, hex(L[j]).upper()[2:].rjust(2*wb, '0'))
+    ##for i in xrange(n):
+    ##  print 'S[%3d] = %s' % (i, hex(S[i]).upper()[2:].rjust(2*wb, '0'))
+
+    i = j = 0
+    A = B = C.MP(0)
+
+    for s in xrange(3*max(c, n)):
+      A = S[i] = rol(me.w, S[i] + A + B, 3)
+      B = L[j] = rol(me.w, L[j] + A + B, (A + B)%(1 << me.d))
+      ##print 'S[%3d] = %s' % (i, hex(S[i]).upper()[2:].rjust(2*wb, '0'))
+      ##print 'L[%3d] = %s' % (j, hex(L[j]).upper()[2:].rjust(2*wb, '0'))
+      i = (i + 1)%n
+      j = (j + 1)%c
+
+    ## Done.
+    me.s = S
+
+  def encrypt(me, x):
+    M = C.MP(0).setbit(me.w) - 1
+    a, b, c, d = map(C.MP.loadl, blocks0(x, me.blksz/4)[0])
+    b = (b + me.s[0])&M
+    d = (d + me.s[1])&M
+    ##print 'B = %s' % (hex(b).upper()[2:].rjust(me.w/4, '0'))
+    ##print 'D = %s' % (hex(d).upper()[2:].rjust(me.w/4, '0'))
+    for i in xrange(2, 2*me.r + 2, 2):
+      t = rol(me.w, 2*b*b + b, me.d)
+      u = rol(me.w, 2*d*d + d, me.d)
+      a = (rol(me.w, a ^ t, u%(1 << me.d)) + me.s[i + 0])&M
+      c = (rol(me.w, c ^ u, t%(1 << me.d)) + me.s[i + 1])&M
+      ##print 'A = %s' % (hex(a).upper()[2:].rjust(me.w/4, '0'))
+      ##print 'C = %s' % (hex(c).upper()[2:].rjust(me.w/4, '0'))
+      a, b, c, d = b, c, d, a
+    a = (a + me.s[2*me.r + 2])&M
+    c = (c + me.s[2*me.r + 3])&M
+    ##print 'A = %s' % (hex(a).upper()[2:].rjust(me.w/4, '0'))
+    ##print 'C = %s' % (hex(c).upper()[2:].rjust(me.w/4, '0'))
+    return C.ByteString(a.storel(me.blksz/4) + b.storel(me.blksz/4) +
+                        c.storel(me.blksz/4) + d.storel(me.blksz/4))
+
+  def decrypt(me, x):
+    M = C.MP(0).setbit(me.w) - 1
+    a, b, c, d = map(C.MP.loadl, blocks0(x, me.blksz/4))
+    c = (c - me.s[2*me.r + 3])&M
+    a = (a - me.s[2*me.r + 2])&M
+    for i in xrange(2*me.r + 1, 1, -2):
+      a, b, c, d = d, a, b, c
+      u = rol(me.w, 2*d*d + d, me.d)
+      t = rol(me.w, 2*b*b + b, me.d)
+      c = ror(me.w, (c - me.s[i + 1])&M, t%(1 << me.d)) ^ u
+      a = ror(me.w, (a - me.s[i + 0])&M, u%(1 << me.d)) ^ t
+    a = (a + s[2*me.r + 2])&M
+    c = (c + s[2*me.r + 3])&M
+    return C.ByteString(a.storel(me.blksz/4) + b.storel(me.blksz/4) +
+                        c.storel(me.blksz/4) + d.storel(me.blksz/4))
+
+for (w, r) in [(8, 16), (16, 16), (24, 16), (32, 16),
+               (32, 20), (48, 16), (64, 16), (96, 16), (128, 16),
+               (192, 16), (256, 16), (400, 16)]:
+  CUSTOM['rc6-%d/%d' % (w, r)] = RC6Cipher(w, r)
+
+###--------------------------------------------------------------------------
+### OMAC (or CMAC).
+
+def omac_masks(E):
+  blksz = E.__class__.blksz
+  p = poly(8*blksz)
+  z = Z(blksz)
+  L = E.encrypt(z)
+  m0 = mul_blk_gf(L, 2, p)
+  m1 = mul_blk_gf(m0, 2, p)
+  return m0, m1
+
+def dump_omac(E):
+  blksz = E.__class__.blksz
+  m0, m1 = omac_masks(E)
+  print 'L = %s' % hex(E.encrypt(Z(blksz)))
+  print 'm0 = %s' % hex(m0)
+  print 'm1 = %s' % hex(m1)
+  for t in xrange(3):
+    print 'v%d = %s' % (t, hex(E.encrypt(C.MP(t).storeb(blksz))))
+    print 'z%d = %s' % (t, hex(omac(E, t, '')))
+
+def omac(E, t, m):
+  blksz = E.__class__.blksz
+  m0, m1 = omac_masks(E)
+  a = Z(blksz)
+  if t is not None: m = C.MP(t).storeb(blksz) + m
+  v, tl = blocks(m, blksz)
+  for x in v: a = E.encrypt(a ^ x)
+  r = blksz - len(tl)
+  if r == 0:
+    a = E.encrypt(a ^ tl ^ m0)
+  else:
+    pad = pad10star(tl, blksz)
+    a = E.encrypt(a ^ pad ^ m1)
+  return a
+
+def cmac(E, m):
+  if VERBOSE: dump_omac(E)
+  return omac(E, None, m),
+
+def cmacgen(bc):
+  return [(0,), (1,),
+          (3*bc.blksz,),
+          (3*bc.blksz - 5,)]
+
+###--------------------------------------------------------------------------
+### Counter mode.
+
+def ctr(E, m, c0):
+  blksz = E.__class__.blksz
+  y = C.WriteBuffer()
+  c = C.MP.loadb(c0)
+  while y.size < len(m):
+    y.put(E.encrypt(c.storeb(blksz)))
+    c += 1
+  return C.ByteString(m) ^ C.ByteString(y)[:len(m)]
+
+###--------------------------------------------------------------------------
+### GCM.
+
+def gcm_mangle(x):
+  y = C.WriteBuffer()
+  for b in x:
+    b = ord(b)
+    bb = 0
+    for i in xrange(8):
+      bb <<= 1
+      if b&1: bb |= 1
+      b >>= 1
+    y.putu8(bb)
+  return C.ByteString(y)
+
+def gcm_mul(x, y):
+  w = len(x)
+  p = poly(8*w)
+  u, v = C.GF.loadl(gcm_mangle(x)), C.GF.loadl(gcm_mangle(y))
+  z = (u*v)%p
+  return gcm_mangle(z.storel(w))
+
+def gcm_pow(x, n):
+  w = len(x)
+  p = poly(8*w)
+  u = C.GF.loadl(gcm_mangle(x))
+  z = pow(u, n, p)
+  return gcm_mangle(z.storel(w))
+
+def gcm_ctr(E, m, c0):
+  y = C.WriteBuffer()
+  pre = c0[:-4]
+  c, = unpack('>L', c0[-4:])
+  while y.size < len(m):
+    c += 1
+    y.put(E.encrypt(pre + pack('>L', c)))
+  return C.ByteString(m) ^ C.ByteString(y)[:len(m)]
+
+def g(what, x, m, a0 = None):
+  n = len(x)
+  if a0 is None: a = Z(n)
+  else: a = a0
+  i = 0
+  for b in blocks0(m, n)[0]:
+    a = gcm_mul(a ^ b, x)
+    if VERBOSE: print '%s[%d] = %s -> %s' % (what, i, hex(b), hex(a))
+    i += 1
+  return a
+
+def gcm_pad(w, x):
+  return C.ByteString(x + Z(-len(x)%w))
+
+def gcm_lens(w, a, b):
+  if w < 12: n = w
+  else: n = w/2
+  return C.ByteString(C.MP(a).storeb(n) + C.MP(b).storeb(n))
+
+def ghash(whata, whatb, x, a, b):
+  w = len(x)
+  ha = g(whata, x, gcm_pad(w, a))
+  hb = g(whatb, x, gcm_pad(w, b))
+  if a:
+    hc = gcm_mul(ha, gcm_pow(x, (len(b) + w - 1)/w)) ^ hb
+    if VERBOSE: print '%s || %s -> %s' % (whata, whatb, hex(hc))
+  else:
+    hc = hb
+  return g(whatb, x, gcm_lens(w, 8*len(a), 8*len(b)), hc)
+
+def gcmenc(E, n, h, m, tsz = None):
+  w = E.__class__.blksz
+  x = E.encrypt(Z(w))
+  if VERBOSE: print 'x = %s' % hex(x)
+  if len(n) + 4 == w: c0 = C.ByteString(n + pack('>L', 1))
+  else: c0 = ghash('?', 'n', x, EMPTY, n)
+  if VERBOSE: print 'c0 = %s' % hex(c0)
+  y = gcm_ctr(E, m, c0)
+  t = ghash('h', 'y', x, h, y) ^ E.encrypt(c0)
+  return y, t
+
+def gcmdec(E, n, h, y, t):
+  w = E.__class__.blksz
+  x = E.encrypt(Z(w))
+  if VERBOSE: print 'x = %s' % hex(x)
+  if len(n) + 4 == w: c0 = C.ByteString(n + pack('>L', 1))
+  else: c0 = ghash('?', 'n', x, EMPTY, n)
+  if VERBOSE: print 'c0 = %s' % hex(c0)
+  m = gcm_ctr(E, y, c0)
+  tt = ghash('h', 'y', x, h, y) ^ E.encrypt(c0)
+  if t == tt: return m,
+  else: return None,
+
+def gcmgen(bc):
+  return [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1),
+          (bc.blksz, 3*bc.blksz, 3*bc.blksz),
+          (bc.blksz - 4, bc.blksz + 3, 3*bc.blksz + 9),
+          (bc.blksz - 1, 3*bc.blksz - 5, 3*bc.blksz + 5)]
+
+def gcm_mul_tests(nbits):
+  print 'gcm-mul%d {' % nbits
+  for i in xrange(64):
+    x = R.block(nbits/8)
+    y = R.block(nbits/8)
+    z = gcm_mul(x, y)
+    print '  %s\n    %s\n    %s;' % (hex(x), hex(y), hex(z))
+  print '}'
+
+###--------------------------------------------------------------------------
+### CCM.
+
+def stbe(n, w): return C.MP(n).storeb(w)
+
+def ccm_fmthdr(blksz, n, hsz, msz, tsz):
+  b = C.WriteBuffer()
+  if blksz == 8:
+    q = blksz - len(n) - 1
+    f = 0
+    if hsz: f |= 0x40
+    f |= (tsz - 1) << 3
+    f |= q - 1
+    b.putu8(f).put(n).put(stbe(msz, q))
+  elif blksz == 16:
+    q = blksz - len(n) - 1
+    f = 0
+    if hsz: f |= 0x40
+    f |= (tsz - 2)/2 << 3
+    f |= q - 1
+    b.putu8(f).put(n).put(stbe(msz, q))
+  else:
+    q = blksz - len(n) - 2
+    f0 = f1 = 0
+    if hsz: f1 |= 0x80
+    f0 |= tsz
+    f1 |= q
+    b.putu8(f0).putu8(f1).put(n).put(stbe(msz, q))
+  b = C.ByteString(b)
+  if VERBOSE: print 'hdr = %s' % hex(b)
+  return b
+
+def ccm_fmtctr(blksz, n, i = 0):
+  b = C.WriteBuffer()
+  if blksz == 8 or blksz == 16:
+    q = blksz - len(n) - 1
+    b.putu8(q - 1).put(n).put(stbe(i, q))
+  else:
+    q = blksz - len(n) - 2
+    b.putu8(0).putu8(q).put(n).put(stbe(i, q))
+  b = C.ByteString(b)
+  if VERBOSE: print 'ctr = %s' % hex(b)
+  return b
+
+def ccmaad(b, h, blksz):
+  hsz = len(h)
+  if not hsz: pass
+  elif hsz < 0xfffe: b.putu16(hsz)
+  elif hsz <= 0xffffffff: b.putu16(0xfffe).putu32(hsz)
+  else: b.putu16(0xffff).putu64(hsz)
+  b.put(h); b.zero((-b.size)%blksz)
+
+def ccmenc(E, n, h, m, tsz = None):
+  blksz = E.__class__.blksz
+  if tsz is None: tsz = blksz
+  b = C.WriteBuffer()
+  b.put(ccm_fmthdr(blksz, n, len(h), len(m), tsz))
+  ccmaad(b, h, blksz)
+  b.put(m); b.zero((-b.size)%blksz)
+  b = C.ByteString(b)
+  a = Z(blksz)
+  v, _ = blocks0(b, blksz)
+  i = 0
+  for x in v:
+    a = E.encrypt(a ^ x)
+    if VERBOSE:
+      print 'b[%d] = %s' % (i, hex(x))
+      print 'a[%d] = %s' % (i + 1, hex(a))
+    i += 1
+  y = ctr(E, a + m, ccm_fmtctr(blksz, n))
+  return C.ByteString(y[blksz:]), C.ByteString(y[0:tsz])
+
+def ccmdec(E, n, h, y, t):
+  blksz = E.__class__.blksz
+  tsz = len(t)
+  b = C.WriteBuffer()
+  b.put(ccm_fmthdr(blksz, n, len(h), len(y), tsz))
+  ccmaad(b, h, blksz)
+  mm = ctr(E, t + Z(blksz - tsz) + y, ccm_fmtctr(blksz, n))
+  u, m = C.ByteString(mm[0:tsz]), C.ByteString(mm[blksz:])
+  b.put(m); b.zero((-b.size)%blksz)
+  b = C.ByteString(b)
+  a = Z(blksz)
+  v, _ = blocks0(b, blksz)
+  i = 0
+  for x in v:
+    a = E.encrypt(a ^ x)
+    if VERBOSE:
+      print 'b[%d] = %s' % (i, hex(x))
+      print 'a[%d] = %s' % (i + 1, hex(a))
+    i += 1
+  if u == a[:tsz]: return m,
+  else: return None,
+
+def ccmgen(bc):
+  bsz = bc.blksz
+  return [(bsz - 5, 0, 0, 4), (bsz - 5, 1, 0, 4), (bsz - 5, 0, 1, 4),
+          (bsz/2 + 1, 3*bc.blksz, 3*bc.blksz),
+          (bsz/2 + 1, 3*bc.blksz - 5, 3*bc.blksz + 5)]
+
+###--------------------------------------------------------------------------
+### EAX.
+
+def eaxenc(E, n, h, m, tsz = None):
+  if VERBOSE:
+    print 'k = %s' % hex(k)
+    print 'n = %s' % hex(n)
+    print 'h = %s' % hex(h)
+    print 'm = %s' % hex(m)
+    dump_omac(E)
+  if tsz is None: tsz = E.__class__.blksz
+  c0 = omac(E, 0, n)
+  y = ctr(E, m, c0)
+  ht = omac(E, 1, h)
+  yt = omac(E, 2, y)
+  if VERBOSE:
+    print 'c0 = %s' % hex(c0)
+    print 'ht = %s' % hex(ht)
+    print 'yt = %s' % hex(yt)
+  return y, C.ByteString((c0 ^ ht ^ yt)[:tsz])
+
+def eaxdec(E, n, h, y, t):
+  if VERBOSE:
+    print 'k = %s' % hex(k)
+    print 'n = %s' % hex(n)
+    print 'h = %s' % hex(h)
+    print 'y = %s' % hex(y)
+    print 't = %s' % hex(t)
+    dump_omac(E)
+  c0 = omac(E, 0, n)
+  m = ctr(E, y, c0)
+  ht = omac(E, 1, h)
+  yt = omac(E, 2, y)
+  if VERBOSE:
+    print 'c0 = %s' % hex(c0)
+    print 'ht = %s' % hex(ht)
+    print 'yt = %s' % hex(yt)
+  if t == (c0 ^ ht ^ yt)[:len(t)]: return m,
+  else: return None,
+
+def eaxgen(bc):
+  return [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1),
+          (bc.blksz, 3*bc.blksz, 3*bc.blksz),
+          (bc.blksz - 1, 3*bc.blksz - 5, 3*bc.blksz + 5)]
+
+###--------------------------------------------------------------------------
+### PMAC.
+
+def ocb_masks(E):
+  blksz = E.__class__.blksz
+  p = poly(8*blksz)
+  x = C.GF(2); xinv = p.modinv(x)
+  z = Z(blksz)
+  L = E.encrypt(z)
+  Lxinv = mul_blk_gf(L, xinv, p)
+  Lgamma = 66*[L]
+  for i in xrange(1, len(Lgamma)):
+    Lgamma[i] = mul_blk_gf(Lgamma[i - 1], x, p)
+  return Lgamma, Lxinv
+
+def dump_ocb(E):
+  Lgamma, Lxinv = ocb_masks(E)
+  print 'L x^-1 = %s' % hex(Lxinv)
+  for i, lg in enumerate(Lgamma[:16]):
+    print 'L x^%d = %s' % (i, hex(lg))
+
+def pmac1(E, m):
+  blksz = E.__class__.blksz
+  Lgamma, Lxinv = ocb_masks(E)
+  a = o = Z(blksz)
+  i = 0
+  v, tl = blocks(m, blksz)
+  for x in v:
+    i += 1
+    b = ntz(i)
+    o ^= Lgamma[b]
+    a ^= E.encrypt(x ^ o)
+    if VERBOSE:
+      print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+  if len(tl) == blksz: a ^= tl ^ Lxinv
+  else: a ^= pad10star(tl, blksz)
+  return E.encrypt(a)
+
+def pmac2(E, m):
+  blksz = E.__class__.blksz
+  p = prim(8*blksz)
+  L = E.encrypt(Z(blksz))
+  o = mul_blk_gf(L, 10, p)
+  a = Z(blksz)
+  v, tl = blocks(m, blksz)
+  for x in v:
+    a ^= E.encrypt(x ^ o)
+    o = mul_blk_gf(o, 2, p)
+  if len(tl) == blksz: a ^= tl ^ mul_blk_gf(o, 3, p)
+  else: a ^= pad10star(tl, blksz) ^ mul_blk_gf(o, 5, p)
+  return E.encrypt(a)
+
+def ocb3_masks(E):
+  Lgamma, _ = ocb_masks(E)
+  Lstar = Lgamma[0]
+  Ldollar = Lgamma[1]
+  return Lstar, Ldollar, Lgamma[2:]
+
+def dump_ocb3(E):
+  Lstar, Ldollar, Lgamma = ocb3_masks(E)
+  print 'L_* = %s' % hex(Lstar)
+  print 'L_$ = %s' % hex(Ldollar)
+  for i, lg in enumerate(Lgamma[:16]):
+    print 'L x^%d = %s' % (i, hex(lg))
+
+def pmac3(E, m):
+  ## Note that `PMAC3' is /not/ a secure MAC.  It depends on other parts of
+  ## OCB3 to prevent a rather easy linear-algebra attack.
+  blksz = E.__class__.blksz
+  Lstar, Ldollar, Lgamma = ocb3_masks(E)
+  a = o = Z(blksz)
+  i = 0
+  v, tl = blocks0(m, blksz)
+  for x in v:
+    i += 1
+    b = ntz(i)
+    o ^= Lgamma[b]
+    a ^= E.encrypt(x ^ o)
+    if VERBOSE:
+      print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+  if tl:
+    o ^= Lstar
+    a ^= E.encrypt(pad10star(tl, blksz) ^ o)
+    if VERBOSE:
+      print 'Z[%d]: * -> %s' % (i, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+  return a
+
+def pmac1_pub(E, m):
+  if VERBOSE: dump_ocb(E)
+  return pmac1(E, m),
+
+def pmacgen(bc):
+  return [(0,), (1,),
+          (3*bc.blksz,),
+          (3*bc.blksz - 5,)]
+
+###--------------------------------------------------------------------------
+### OCB.
+
+def ocb1enc(E, n, h, m, tsz = None):
+  ## This is OCB1.PMAC1 from Rogaway's `Authenticated-Encryption with
+  ## Associated-Data'.
+  blksz = E.__class__.blksz
+  if VERBOSE: dump_ocb(E)
+  Lgamma, Lxinv = ocb_masks(E)
+  if tsz is None: tsz = blksz
+  a = Z(blksz)
+  o = E.encrypt(n ^ Lgamma[0])
+  if VERBOSE: print 'R = %s' % hex(o)
+  i = 0
+  y = C.WriteBuffer()
+  v, tl = blocks(m, blksz)
+  for x in v:
+    i += 1
+    b = ntz(i)
+    o ^= Lgamma[b]
+    a ^= x
+    if VERBOSE:
+      print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+    y.put(E.encrypt(x ^ o) ^ o)
+  i += 1
+  b = ntz(i)
+  o ^= Lgamma[b]
+  n = len(tl)
+  if VERBOSE:
+    print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+    print 'LEN = %s' % hex(C.MP(8*n).storeb(blksz))
+  yfinal = E.encrypt(C.MP(8*n).storeb(blksz) ^ Lxinv ^ o)
+  cfinal = tl ^ yfinal[:n]
+  a ^= o ^ (tl + yfinal[n:])
+  y.put(cfinal)
+  t = E.encrypt(a)
+  if h: t ^= pmac1(E, h)
+  return C.ByteString(y), C.ByteString(t[:tsz])
+
+def ocb1dec(E, n, h, y, t):
+  ## This is OCB1.PMAC1 from Rogaway's `Authenticated-Encryption with
+  ## Associated-Data'.
+  blksz = E.__class__.blksz
+  if VERBOSE: dump_ocb(E)
+  Lgamma, Lxinv = ocb_masks(E)
+  a = Z(blksz)
+  o = E.encrypt(n ^ Lgamma[0])
+  if VERBOSE: print 'R = %s' % hex(o)
+  i = 0
+  m = C.WriteBuffer()
+  v, tl = blocks(y, blksz)
+  for x in v:
+    i += 1
+    b = ntz(i)
+    o ^= Lgamma[b]
+    if VERBOSE:
+      print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+    u = E.decrypt(x ^ o) ^ o
+    m.put(u)
+    a ^= u
+  i += 1
+  b = ntz(i)
+  o ^= Lgamma[b]
+  n = len(tl)
+  if VERBOSE:
+    print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+    print 'LEN = %s' % hex(C.MP(8*n).storeb(blksz))
+  yfinal = E.encrypt(C.MP(8*n).storeb(blksz) ^ Lxinv ^ o)
+  mfinal = tl ^ yfinal[:n]
+  a ^= o ^ (mfinal + yfinal[n:])
+  m.put(mfinal)
+  u = E.encrypt(a)
+  if h: u ^= pmac1(E, h)
+  if t == u[:len(t)]: return C.ByteString(m),
+  else: return None,
+
+def ocb2enc(E, n, h, m, tsz = None):
+  ## For OCB2, it's important for security that n = log_x (x + 1) is large in
+  ## the field representations of GF(2^w) used -- in fact, we need more, that
+  ## i n (mod 2^w - 1) is large for i in {4, -3, -2, -1, 1, 2, 3, 4}.  The
+  ## original paper lists the values for 64 and 128, but we support other
+  ## block sizes, so here's the result of the (rather large, in some cases)
+  ## computation.
+  ##
+  ## Block size           log_x (x + 1)
+  ##
+  ##       64             9686038906114705801
+  ##       96             63214690573408919568138788065
+  ##      128             338793687469689340204974836150077311399
+  ##      192             161110085006042185925119981866940491651092686475226538785
+  ##      256             22928580326165511958494515843249267194111962539778797914076675796261938307298
+
+  blksz = E.__class__.blksz
+  if tsz is None: tsz = blksz
+  p = prim(8*blksz)
+  L = E.encrypt(n)
+  o = mul_blk_gf(L, 2, p)
+  a = Z(blksz)
+  v, tl = blocks(m, blksz)
+  y = C.WriteBuffer()
+  for x in v:
+    a ^= x
+    y.put(E.encrypt(x ^ o) ^ o)
+    o = mul_blk_gf(o, 2, p)
+  n = len(tl)
+  yfinal = E.encrypt(C.MP(8*n).storeb(blksz) ^ o)
+  cfinal = tl ^ yfinal[:n]
+  a ^= (tl + yfinal[n:]) ^ mul_blk_gf(o, 3, p)
+  y.put(cfinal)
+  t = E.encrypt(a)
+  if h: t ^= pmac2(E, h)
+  return C.ByteString(y), C.ByteString(t[:tsz])
+
+def ocb2dec(E, n, h, y, t):
+  blksz = E.__class__.blksz
+  p = prim(8*blksz)
+  L = E.encrypt(n)
+  o = mul_blk_gf(L, 2, p)
+  a = Z(blksz)
+  v, tl = blocks(y, blksz)
+  m = C.WriteBuffer()
+  for x in v:
+    u = E.encrypt(x ^ o) ^ o
+    y.put(u)
+    a ^= u
+    o = mul_blk_gf(o, 2, p)
+  n = len(tl)
+  yfinal = E.encrypt(C.MP(8*n).storeb(blksz) ^ o)
+  mfinal = tl ^ yfinal[:n]
+  a ^= (mfinal + yfinal[n:]) ^ mul_blk_gf(o, 3, p)
+  m.put(mfinal)
+  u = E.encrypt(a)
+  if h: u ^= pmac2(E, h)
+  if t == u[:len(t)]: return C.ByteString(m),
+  else: return None,
+
+OCB3_STRETCH = {  4: ( 4,  17),
+                  8: ( 5,  25),
+                 12: ( 6,  33),
+                 16: ( 6,   8),
+                 24: ( 7,  40),
+                 32: ( 8,   1),
+                 48: ( 8,  80),
+                 64: ( 8, 176),
+                 96: ( 9, 160),
+                128: ( 9, 352),
+                200: (10, 192) }
+
+def ocb3nonce(E, n, tsz):
+
+  ## Figure out how much we need to glue onto the nonce.  This ends up being
+  ## [t mod w]_v || 0^p || 1 || N, where w is the block size in bits, t is
+  ## the tag length in bits, v = floor(log_2(w - 1)) + 1, and p = w - l(N) -
+  ## v - 1.  But this is an annoying way to think about it because of the
+  ## byte misalignment.  Instead, think of it as a byte-aligned prefix
+  ## encoding the tag and an `is the nonce full-length' flag, followed by
+  ## optional padding, and then the nonce:
+  ##
+  ##    F || N                  if l(N) = w - f
+  ##    F || 0^p || 1 || N      otherwise
+  ##
+  ## where F is [t mod w]_v || 0^{f-v-1} || b; f = floor(log_2(w - 1)) + 2;
+  ## b is 1 if l(N) = w - f, or 0 otherwise; and p = w - f - l(N) - 1.
+  blksz = E.__class__.blksz
+  tszbits = min(C.MP(8*blksz - 1).nbits, 8)
+  fwd = tszbits/8 + 1
+  f = 8*(tsz%blksz) << + 8*fwd - tszbits
+
+  ## Form the augmented nonce.
+  nb = C.WriteBuffer()
+  nsz, nwd = len(n), blksz - fwd
+  if nsz == nwd: f |= 1
+  nb.put(C.MP(f).storeb(fwd))
+  if nsz < nwd: nb.zero(nwd - nsz - 1).putu8(1)
+  nb.put(n)
+  nn = C.ByteString(nb)
+  if VERBOSE: print 'aug-nonce = %s' % hex(nn)
+
+  ## Calculate the initial offset.
+  split, shift = OCB3_STRETCH[blksz]
+  t2pw = C.MP(0).setbit(8*blksz) - 1
+  lomask = (C.MP(0).setbit(split) - 1)
+  himask = ~lomask
+  top, bottom = nn&himask.storeb2c(blksz), C.MP.loadb(nn)&lomask
+  ktop = C.MP.loadb(E.encrypt(top))
+  stretch = (ktop << 8*blksz) | (ktop ^ (ktop << shift)&t2pw)
+  o = (stretch >> 8*blksz - bottom).storeb(blksz)
+  if VERBOSE:
+    print 'stretch = %s' % hex(stretch.storeb(2*blksz))
+    print 'Z[0] = %s' % hex(o)
+
+  return o
+
+def ocb3enc(E, n, h, m, tsz = None):
+  blksz = E.__class__.blksz
+  if tsz is None: tsz = blksz
+  Lstar, Ldollar, Lgamma = ocb3_masks(E)
+  if VERBOSE: dump_ocb3(E)
+
+  ## Set things up.
+  o = ocb3nonce(E, n, tsz)
+  a = C.ByteString.zero(blksz)
+
+  ## Split the message into blocks.
+  i = 0
+  y = C.WriteBuffer()
+  v, tl = blocks0(m, blksz)
+  for x in v:
+    i += 1
+    b = ntz(i)
+    o ^= Lgamma[b]
+    a ^= x
+    if VERBOSE:
+      print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+    y.put(E.encrypt(x ^ o) ^ o)
+  if tl:
+    o ^= Lstar
+    n = len(tl)
+    pad = E.encrypt(o)
+    a ^= pad10star(tl, blksz)
+    if VERBOSE:
+      print 'Z[%d]: * -> %s' % (i, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+    y.put(tl ^ pad[0:n])
+  o ^= Ldollar
+  t = E.encrypt(a ^ o) ^ pmac3(E, h)
+  return C.ByteString(y), C.ByteString(t[:tsz])
+
+def ocb3dec(E, n, h, y, t):
+  blksz = E.__class__.blksz
+  tsz = len(t)
+  Lstar, Ldollar, Lgamma = ocb3_masks(E)
+  if VERBOSE: dump_ocb3(E)
+
+  ## Set things up.
+  o = ocb3nonce(E, n, tsz)
+  a = C.ByteString.zero(blksz)
+
+  ## Split the message into blocks.
+  i = 0
+  m = C.WriteBuffer()
+  v, tl = blocks0(y, blksz)
+  for x in v:
+    i += 1
+    b = ntz(i)
+    o ^= Lgamma[b]
+    if VERBOSE:
+      print 'Z[%d]: %d -> %s' % (i, b, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+    u = E.encrypt(x ^ o) ^ o
+    m.put(u)
+    a ^= u
+  if tl:
+    o ^= Lstar
+    n = len(tl)
+    pad = E.encrypt(o)
+    if VERBOSE:
+      print 'Z[%d]: * -> %s' % (i, hex(o))
+      print 'A[%d]: %s' % (i, hex(a))
+    u = tl ^ pad[0:n]
+    m.put(u)
+    a ^= pad10star(u, blksz)
+  o ^= Ldollar
+  u = E.encrypt(a ^ o) ^ pmac3(E, h)
+  if t == u[:tsz]: return C.ByteString(m),
+  else: return None,
+
+def ocbgen(bc):
+  w = bc.blksz
+  return [(w, 0, 0), (w, 1, 0), (w, 0, 1),
+          (w, 0, 3*w),
+          (w, 3*w, 3*w),
+          (w, 0, 3*w + 5),
+          (w, 3*w - 5, 3*w + 5)]
+
+def ocb3gen(bc):
+  w = bc.blksz
+  return [(w - 2, 0, 0), (w - 2, 1, 0), (w - 2, 0, 1),
+          (w - 5, 0, 3*w),
+          (w - 3, 3*w, 3*w),
+          (w - 2, 0, 3*w + 5),
+          (w - 2, 3*w - 5, 3*w + 5)]
+
+def ocb3_mct(bc, ksz, tsz):
+  k = C.ByteString(C.WriteBuffer().zero(ksz - 4).putu32(8*tsz))
+  E = bc(k)
+  n = C.MP(1)
+  nw = bc.blksz - 4
+  cbuf = C.WriteBuffer()
+  for i in xrange(128):
+    s = C.ByteString.zero(i)
+    y, t = ocb3enc(E, n.storeb(nw), s, s, tsz); n += 1; cbuf.put(y).put(t)
+    y, t = ocb3enc(E, n.storeb(nw), EMPTY, s, tsz); n += 1; cbuf.put(y).put(t)
+    y, t = ocb3enc(E, n.storeb(nw), s, EMPTY, tsz); n += 1; cbuf.put(y).put(t)
+  _, t = ocb3enc(E, n.storeb(nw), C.ByteString(cbuf), EMPTY, tsz)
+  print hex(t)
+
+def ocb3_mct2(bc):
+  k = C.bytes('000102030405060708090a0b0c0d0e0f')
+  E = bc(k)
+  tsz = min(E.blksz, 32)
+  n = C.MP(1)
+  cbuf = C.WriteBuffer()
+  for i in xrange(128):
+    sbuf = C.WriteBuffer()
+    for j in xrange(i): sbuf.putu8(j)
+    s = C.ByteString(sbuf)
+    y, t = ocb3enc(E, n.storeb(2), s, s, tsz); n += 1; cbuf.put(y).put(t)
+    y, t = ocb3enc(E, n.storeb(2), EMPTY, s, tsz); n += 1; cbuf.put(y).put(t)
+    y, t = ocb3enc(E, n.storeb(2), s, EMPTY, tsz); n += 1; cbuf.put(y).put(t)
+  _, t = ocb3enc(E, n.storeb(2), C.ByteString(cbuf), EMPTY, tsz)
+  print hex(t)
+
+###--------------------------------------------------------------------------
+### Main program.
+
+class struct (object):
+  def __init__(me, **kw):
+    me.__dict__.update(kw)
+
+binarg = struct(mk = R.block, parse = C.bytes, show = safehex)
+intarg = struct(mk = lambda x: x, parse = int, show = None)
+
+MODEMAP = { 'eax-enc': (eaxgen, 3*[binarg] + [intarg], eaxenc),
+            'eax-dec': (dummygen, 4*[binarg], eaxdec),
+            'ccm-enc': (ccmgen, 3*[binarg] + [intarg], ccmenc),
+            'ccm-dec': (dummygen, 4*[binarg], ccmdec),
+            'cmac': (cmacgen, [binarg], cmac),
+            'gcm-enc': (gcmgen, 3*[binarg] + [intarg], gcmenc),
+            'gcm-dec': (dummygen, 4*[binarg], gcmdec),
+            'ocb1-enc': (ocbgen, 3*[binarg] + [intarg], ocb1enc),
+            'ocb1-dec': (dummygen, 4*[binarg], ocb1dec),
+            'ocb2-enc': (ocbgen, 3*[binarg] + [intarg], ocb2enc),
+            'ocb2-dec': (dummygen, 4*[binarg], ocb2dec),
+            'ocb3-enc': (ocb3gen, 3*[binarg] + [intarg], ocb3enc),
+            'ocb3-dec': (dummygen, 4*[binarg], ocb3dec),
+            'pmac1': (pmacgen, [binarg], pmac1_pub) }
+
+mode = argv[1]
+if len(argv) == 3 and mode == 'gcm-mul':
+  VERBOSE = False
+  nbits = int(argv[2])
+  gcm_mul_tests(nbits)
+  exit(0)
+bc = None
+for d in CUSTOM, C.gcprps:
+  try: bc = d[argv[2]]
+  except KeyError: pass
+  else: break
+if bc is None: raise KeyError, argv[2]
+if len(argv) == 5 and mode == 'ocb3-mct':
+  VERBOSE = False
+  ksz, tsz = int(argv[3]), int(argv[4])
+  ocb3_mct(bc, ksz, tsz)
+  exit(0)
+if len(argv) == 3 and mode == 'ocb3-mct2':
+  VERBOSE = False
+  ocb3_mct2(bc)
+  exit(0)
+if len(argv) == 3:
+  VERBOSE = False
+  gen, argty, func = MODEMAP[mode]
+  if mode.endswith('-enc'): mode = mode[:-4]
+  print '%s-%s {' % (bc.name, mode)
+  for ksz in keylens(bc.keysz):
+    for argvals in gen(bc):
+      k = R.block(ksz)
+      args = [t.mk(a) for t, a in izip(argty, argvals)]
+      rets = func(bc(k), *args)
+      print '  %s' % safehex(k)
+      for t, a in izip(argty, args):
+        if t.show: print '    %s' % t.show(a)
+      for r, lastp in with_lastp(rets):
+        print '    %s%s' % (safehex(r), lastp and ';' or '')
+  print '}'
+else:
+  VERBOSE = True
+  k = C.bytes(argv[3])
+  gen, argty, func = MODEMAP[mode]
+  args = [t.parse(a) for t, a in izip(argty, argv[4:])]
+  rets = func(bc(k), *args)
+  for r in rets:
+    if r is None: print "X"
+    else: print hex(r)
+
+###----- That's all, folks --------------------------------------------------
diff --git a/utils/gcm-ref b/utils/gcm-ref
new file mode 100755 (executable)
index 0000000..ccbf432
--- /dev/null
@@ -0,0 +1,502 @@
+#! /usr/bin/python
+### -*- coding: utf-8 -*-
+
+from sys import argv, exit
+
+import catacomb as C
+
+###--------------------------------------------------------------------------
+### Random utilities.
+
+def words(s):
+  """Split S into 32-bit pieces and report their values as hex."""
+  return ' '.join('%08x' % C.MP.loadb(s[i:i + 4])
+                  for i in xrange(0, len(s), 4))
+
+def words_64(s):
+  """Split S into 64-bit pieces and report their values as hex."""
+  return ' '.join('%016x' % C.MP.loadb(s[i:i + 8])
+                  for i in xrange(0, len(s), 8))
+
+def repmask(val, wd, n):
+  """Return a mask consisting of N copies of the WD-bit value VAL."""
+  v = C.GF(val)
+  a = C.GF(0)
+  for i in xrange(n): a = (a << wd) | v
+  return a
+
+def combs(things, k):
+  """Iterate over all possible combinations of K of the THINGS."""
+  ii = range(k)
+  n = len(things)
+  while True:
+    yield [things[i] for i in ii]
+    for j in xrange(k):
+      if j == k - 1: lim = n
+      else: lim = ii[j + 1]
+      i = ii[j] + 1
+      if i < lim:
+        ii[j] = i
+        break
+      ii[j] = j
+    else:
+      return
+
+POLYMAP = {}
+
+def poly(nbits):
+  """
+  Return the lexically first irreducible polynomial of degree NBITS of lowest
+  weight.
+  """
+  try: return POLYMAP[nbits]
+  except KeyError: pass
+  base = C.GF(0).setbit(nbits).setbit(0)
+  for k in xrange(1, nbits, 2):
+    for cc in combs(range(1, nbits), k):
+      p = base + sum(C.GF(0).setbit(c) for c in cc)
+      if p.irreduciblep(): POLYMAP[nbits] = p; return p
+  raise ValueError, nbits
+
+def gcm_mangle(x):
+  """Flip the bits within each byte according to GCM's insane convention."""
+  y = C.WriteBuffer()
+  for b in x:
+    b = ord(b)
+    bb = 0
+    for i in xrange(8):
+      bb <<= 1
+      if b&1: bb |= 1
+      b >>= 1
+    y.putu8(bb)
+  return y.contents
+
+def endswap_words_32(x):
+  """End-swap each 32-bit word of X."""
+  x = C.ReadBuffer(x)
+  y = C.WriteBuffer()
+  while x.left: y.putu32l(x.getu32b())
+  return y.contents
+
+def endswap_words_64(x):
+  """End-swap each 64-bit word of X."""
+  x = C.ReadBuffer(x)
+  y = C.WriteBuffer()
+  while x.left: y.putu64l(x.getu64b())
+  return y.contents
+
+def endswap_bytes(x):
+  """End-swap X by bytes."""
+  y = C.WriteBuffer()
+  for ch in reversed(x): y.put(ch)
+  return y.contents
+
+def gfmask(n):
+  return C.GF(C.MP(0).setbit(n) - 1)
+
+def gcm_mul(x, y):
+  """Multiply X and Y according to the GCM rules."""
+  w = len(x)
+  p = poly(8*w)
+  u, v = C.GF.loadl(gcm_mangle(x)), C.GF.loadl(gcm_mangle(y))
+  z = (u*v)%p
+  return gcm_mangle(z.storel(w))
+
+DEMOMAP = {}
+def demo(func):
+  name = func.func_name
+  assert(name.startswith('demo_'))
+  DEMOMAP[name[5:].replace('_', '-')] = func
+  return func
+
+def iota(i = 0):
+  vi = [i]
+  def next(): vi[0] += 1; return vi[0] - 1
+  return next
+
+###--------------------------------------------------------------------------
+### Portable table-driven implementation.
+
+def shift_left(x):
+  """Given a field element X (in external format), return X t."""
+  w = len(x)
+  p = poly(8*w)
+  return gcm_mangle(C.GF.storel((C.GF.loadl(gcm_mangle(x)) << 1)%p))
+
+def table_common(u, v, flip, getword, ixmask):
+  """
+  Multiply U by V using table lookup; common for `table-b' and `table-l'.
+
+  This matches the `simple_mulk_...' implementation in `gcm.c'.  One-entry
+  per bit is the best we can manage if we want a constant-time
+  implementation: processing n bits at a time means we need to scan
+  (2^n - 1)/n times as much memory.
+
+    * FLIP is a function (assumed to be an involution) on one argument X to
+      convert X from external format to table-entry format or back again.
+
+    * GETWORD is a function on one argument B to retrieve the next 32-bit
+      chunk of a field element held in a `ReadBuffer'.  Bits within a word
+      are processed most-significant first.
+
+    * IXMASK is a mask XORed into table indices to permute the table so that
+      it's order matches that induced by GETWORD.
+
+  The table is built such that tab[i XOR IXMASK] = U t^i.
+  """
+  w = len(u); assert(w == len(v))
+  a = C.ByteString.zero(w)
+  tab = [None]*(8*w)
+  for i in xrange(8*w):
+    print ';; %9s = %7s = %s' % ('utab[%d]' % i, 'u t^%d' % i, words(u))
+    tab[i ^ ixmask] = flip(u)
+    u = shift_left(u)
+  v = C.ReadBuffer(v)
+  i = 0
+  while v.left:
+    t = getword(v)
+    for j in xrange(32):
+      bit = (t >> 31)&1
+      if bit: a ^= tab[i]
+      print ';; %6s = %d: a <- %s [%9s = %s]' % \
+        ('v[%d]' % (i ^ ixmask), bit, words(a),
+         'utab[%d]' % (i ^ ixmask), words(tab[i]))
+      i += 1; t <<= 1
+  return flip(a)
+
+@demo
+def demo_table_b(u, v):
+  """Big-endian table lookup."""
+  return table_common(u, v, lambda x: x, lambda b: b.getu32b(), 0)
+
+@demo
+def demo_table_l(u, v):
+  """Little-endian table lookup."""
+  return table_common(u, v, endswap_words, lambda b: b.getu32l(), 0x18)
+
+###--------------------------------------------------------------------------
+### Implementation using 64×64->128-bit binary polynomial multiplication.
+
+_i = iota()
+TAG_INPUT_U = _i()
+TAG_INPUT_V = _i()
+TAG_KPIECE_U = _i()
+TAG_KPIECE_V = _i()
+TAG_PRODPIECE = _i()
+TAG_PRODSUM = _i()
+TAG_PRODUCT = _i()
+TAG_SHIFTED = _i()
+TAG_REDCBITS = _i()
+TAG_REDCFULL = _i()
+TAG_REDCMIX = _i()
+TAG_OUTPUT = _i()
+
+def split_gf(x, n):
+  n /= 8
+  return [C.GF.loadb(x[i:i + n]) for i in xrange(0, len(x), n)]
+
+def join_gf(xx, n):
+  x = C.GF(0)
+  for i in xrange(len(xx)): x = (x << n) | xx[i]
+  return x
+
+def present_gf(x, w, n, what):
+  firstp = True
+  m = gfmask(n)
+  for i in xrange(0, w, 128):
+    print ';; %12s%c         =%s' % \
+      (firstp and what or '',
+       firstp and ':' or ' ',
+       ''.join([j < w
+                and '          0x%s' % hex(((x >> j)&m).storeb(n/8))
+                or ''
+                for j in xrange(i, i + 128, n)]))
+    firstp = False
+
+def present_gf_pclmul(tag, wd, x, w, n, what):
+  if tag != TAG_PRODPIECE: present_gf(x, w, n, what)
+
+def reverse(x, w):
+  return C.GF.loadl(x.storeb(w/8))
+
+def rev32(x):
+  w = x.noctets
+  m_ffff = repmask(0xffff, 32, w/4)
+  m_ff = repmask(0xff, 16, w/2)
+  x = ((x&m_ffff) << 16) | ((x >> 16)&m_ffff)
+  x = ((x&m_ff) << 8) | ((x >> 8)&m_ff)
+  return x
+
+def rev8(x):
+  w = x.noctets
+  m_0f = repmask(0x0f, 8, w)
+  m_33 = repmask(0x33, 8, w)
+  m_55 = repmask(0x55, 8, w)
+  x = ((x&m_0f) << 4) | ((x >> 4)&m_0f)
+  x = ((x&m_33) << 2) | ((x >> 2)&m_33)
+  x = ((x&m_55) << 1) | ((x >> 1)&m_55)
+  return x
+
+def present_gf_mullp64(tag, wd, x, w, n, what):
+  if tag == TAG_PRODPIECE or tag == TAG_REDCFULL:
+    return
+  elif (wd == 128 or wd == 64) and TAG_PRODSUM <= tag <= TAG_PRODUCT:
+    y = x
+  elif (wd == 96 or wd == 192 or wd == 256) and \
+       TAG_PRODSUM <= tag < TAG_OUTPUT:
+    y = x
+  else:
+    xx = x.storeb(w/8)
+    extra = len(xx)%8
+    if extra: xx += C.ByteString.zero(8 - extra)
+    yb = C.WriteBuffer()
+    for i in xrange(len(xx), 0, -8): yb.put(xx[i - 8:i])
+    y = C.GF.loadb(yb.contents)
+  present_gf(y, (w + 63)&~63, n, what)
+
+def present_gf_pmull(tag, wd, x, w, n, what):
+  if tag == TAG_PRODPIECE or tag == TAG_REDCFULL or tag == TAG_SHIFTED:
+    return
+  elif tag == TAG_INPUT_V or tag == TAG_KPIECE_V:
+    bx = C.ReadBuffer(x.storeb(w/8))
+    by = C.WriteBuffer()
+    while bx.left: chunk = bx.get(8); by.put(chunk).put(chunk)
+    x = C.GF.loadb(by.contents)
+    w *= 2
+  elif TAG_PRODSUM <= tag <= TAG_PRODUCT:
+    x <<= 1
+  y = reverse(rev8(x), w)
+  present_gf(y, w, n, what)
+
+def poly64_mul_simple(u, v, presfn, wd, dispwd, mulwd, uwhat, vwhat):
+  """
+  Multiply U by V, returning the product.
+
+  This is the fallback long multiplication.
+  """
+
+  uw, vw = 8*len(u), 8*len(v)
+
+  ## We start by carving the operands into 64-bit pieces.  This is
+  ## straightforward except for the 96-bit case, where we end up with two
+  ## short pieces which we pad at the beginning.
+  if uw%mulwd: pad = (-uw)%mulwd; u += C.ByteString.zero(pad); uw += pad
+  if vw%mulwd: pad = (-uw)%mulwd; v += C.ByteString.zero(pad); vw += pad
+  uu = split_gf(u, mulwd)
+  vv = split_gf(v, mulwd)
+
+  ## Report and accumulate the individual product pieces.
+  x = C.GF(0)
+  ulim, vlim = uw/mulwd, vw/mulwd
+  for i in xrange(ulim + vlim - 2, -1, -1):
+    t = C.GF(0)
+    for j in xrange(max(0, i - vlim + 1), min(vlim, i + 1)):
+      s = uu[ulim - 1 - i + j]*vv[vlim - 1 - j]
+      presfn(TAG_PRODPIECE, wd, s, 2*mulwd, dispwd,
+             '%s_%d %s_%d' % (uwhat, i - j, vwhat, j))
+      t += s
+    presfn(TAG_PRODSUM, wd, t, 2*mulwd, dispwd,
+           '(%s %s)_%d' % (uwhat, vwhat, ulim + vlim - 2 - i))
+    x += t << (mulwd*i)
+  presfn(TAG_PRODUCT, wd, x, uw + vw, dispwd, '%s %s' % (uwhat, vwhat))
+
+  return x
+
+def poly64_mul_karatsuba(u, v, klimit, presfn, wd,
+                         dispwd, mulwd, uwhat, vwhat):
+  """
+  Multiply U by V, returning the product.
+
+  If the length of U and V is at least KLIMIT, and the operands are otherwise
+  suitable, then do Karatsuba--Ofman multiplication; otherwise, delegate to
+  `poly64_mul_simple'.
+  """
+  w = 8*len(u)
+
+  if w < klimit or w != 8*len(v) or w%(2*mulwd) != 0:
+    return poly64_mul_simple(u, v, presfn, wd, dispwd, mulwd, uwhat, vwhat)
+
+  hw = w/2
+  u0, u1 = u[:hw/8], u[hw/8:]
+  v0, v1 = v[:hw/8], v[hw/8:]
+  uu, vv = u0 ^ u1, v0 ^ v1
+
+  presfn(TAG_KPIECE_U, wd, C.GF.loadb(uu), hw, dispwd, '%s*' % uwhat)
+  presfn(TAG_KPIECE_V, wd, C.GF.loadb(vv), hw, dispwd, '%s*' % vwhat)
+  uuvv = poly64_mul_karatsuba(uu, vv, klimit, presfn, wd, dispwd, mulwd,
+                              '%s*' % uwhat, '%s*' % vwhat)
+
+  presfn(TAG_KPIECE_U, wd, C.GF.loadb(u0), hw, dispwd, '%s0' % uwhat)
+  presfn(TAG_KPIECE_V, wd, C.GF.loadb(v0), hw, dispwd, '%s0' % vwhat)
+  u0v0 = poly64_mul_karatsuba(u0, v0, klimit, presfn, wd, dispwd, mulwd,
+                              '%s0' % uwhat, '%s0' % vwhat)
+
+  presfn(TAG_KPIECE_U, wd, C.GF.loadb(u1), hw, dispwd, '%s1' % uwhat)
+  presfn(TAG_KPIECE_V, wd, C.GF.loadb(v1), hw, dispwd, '%s1' % vwhat)
+  u1v1 = poly64_mul_karatsuba(u1, v1, klimit, presfn, wd, dispwd, mulwd,
+                              '%s1' % uwhat, '%s1' % vwhat)
+
+  uvuv = uuvv + u0v0 + u1v1
+  presfn(TAG_PRODSUM, wd, uvuv, w, dispwd, '%s!%s' % (uwhat, vwhat))
+
+  x = u1v1 + (uvuv << hw) + (u0v0 << w)
+  presfn(TAG_PRODUCT, wd, x, 2*w, dispwd, '%s %s' % (uwhat, vwhat))
+  return x
+
+def poly64_common(u, v, presfn, dispwd = 32, mulwd = 64, redcwd = 32,
+                  klimit = 256):
+  """
+  Multiply U by V using a primitive 64-bit binary polynomial mutliplier.
+
+  Such a multiplier exists as the appallingly-named `pclmul[lh]q[lh]qdq' on
+  x86, and as `vmull.p64'/`pmull' on ARM.
+
+  Operands arrive in a `register format', which is a byte-swapped variant of
+  the external format.  Implementations differ on the precise details,
+  though.
+  """
+
+  ## We work in two main phases: first, calculate the full double-width
+  ## product; and, second, reduce it modulo the field polynomial.
+
+  w = 8*len(u); assert(w == 8*len(v))
+  p = poly(w)
+  presfn(TAG_INPUT_U, w, C.GF.loadb(u), w, dispwd, 'u')
+  presfn(TAG_INPUT_V, w, C.GF.loadb(v), w, dispwd, 'v')
+
+  ## So, on to the first part: the multiplication.
+  x = poly64_mul_karatsuba(u, v, klimit, presfn, w, dispwd, mulwd, 'u', 'v')
+
+  ## Now we have to shift everything up one bit to account for GCM's crazy
+  ## bit ordering.
+  y = x << 1
+  if w == 96: y >>= 64
+  presfn(TAG_SHIFTED, w, y, 2*w, dispwd, 'y')
+
+  ## Now for the reduction.
+  ##
+  ## Our polynomial has the form p = t^d + r where r = SUM_{0<=i<d} r_i t^i,
+  ## with each r_i either 0 or 1.  Because we choose the lexically earliest
+  ## irreducible polynomial with the necessary degree, r_i = 1 happens only
+  ## for a small number of tiny i.  In our field, we have t^d = r.
+  ##
+  ## We carve the product into convenient n-bit pieces, for some n dividing d
+  ## -- typically n = 32 or 64.  Let d = m n, and write y = SUM_{0<=i<2m} y_i
+  ## t^{ni}.  The upper portion, the y_i with i >= m, needs reduction; but
+  ## y_i t^{ni} = y_i r t^{n(i-m)}, so we just multiply the top half by r and
+  ## add it to the bottom half.  This all depends on r_i = 0 for all i >=
+  ## n/2.  We process each nonzero coefficient of r separately, in two
+  ## passes.
+  ##
+  ## Multiplying a chunk y_i by some t^j is the same as shifting it left by j
+  ## bits (or would be if GCM weren't backwards, but let's not worry about
+  ## that right now).  The high j bits will spill over into the next chunk,
+  ## while the low n - j bits will stay where they are.  It's these high bits
+  ## which cause trouble -- particularly the high bits of the top chunk,
+  ## since we'll add them on to y_m, which will need further reduction.  But
+  ## only the topmost j bits will do this.
+  ##
+  ## The trick is that we do all of the bits which spill over first -- all of
+  ## the top j bits in each chunk, for each j -- in one pass, and then a
+  ## second pass of all the bits which don't.  Because j, j' < n/2 for any
+  ## two nonzero coefficient degrees j and j', we have j + j' < n whence j <
+  ## n - j' -- so all of the bits contributed to y_m will be handled in the
+  ## second pass when we handle the bits that don't spill over.
+  rr = [i for i in xrange(1, w) if p.testbit(i)]
+  m = gfmask(redcwd)
+
+  ## Handle the spilling bits.
+  yy = split_gf(y.storeb(w/4), redcwd)
+  b = C.GF(0)
+  for rj in rr:
+    br = [(yi << (redcwd - rj))&m for yi in yy[w/redcwd:]]
+    presfn(TAG_REDCBITS, w, join_gf(br, redcwd), w, dispwd, 'b(%d)' % rj)
+    b += join_gf(br, redcwd) << (w - redcwd)
+  presfn(TAG_REDCFULL, w, b, 2*w, dispwd, 'b')
+  s = y + b
+  presfn(TAG_REDCMIX, w, s, 2*w, dispwd, 's')
+
+  ## Handle the nonspilling bits.
+  ss = split_gf(s.storeb(w/4), redcwd)
+  a = C.GF(0)
+  for rj in rr:
+    ar = [si >> rj for si in ss[w/redcwd:]]
+    presfn(TAG_REDCBITS, w, join_gf(ar, redcwd), w, dispwd, 'a(%d)' % rj)
+    a += join_gf(ar, redcwd)
+  presfn(TAG_REDCFULL, w, a, w, dispwd, 'a')
+
+  ## Mix everything together.
+  m = gfmask(w)
+  z = (s&m) + (s >> w) + a
+  presfn(TAG_OUTPUT, w, z, w, dispwd, 'z')
+
+  ## And we're done.
+  return z.storeb(w/8)
+
+@demo
+def demo_pclmul(u, v):
+  return poly64_common(u, v, presfn = present_gf_pclmul)
+
+@demo
+def demo_vmullp64(u, v):
+  w = 8*len(u)
+  return poly64_common(u, v, presfn = present_gf_mullp64,
+                       redcwd = w%64 == 32 and 32 or 64)
+
+@demo
+def demo_pmull(u, v):
+  w = 8*len(u)
+  return poly64_common(u, v, presfn = present_gf_pmull,
+                       redcwd = w%64 == 32 and 32 or 64)
+
+###--------------------------------------------------------------------------
+### @@@ Random debris to be deleted. @@@
+
+def cutting_room_floor():
+
+  x = C.bytes('cde4bef260d7bcda163547d348b7551195e77022907dd1df')
+  y = C.bytes('f7dac5c9941d26d0c6eb14ad568f86edd1dc9268eeee5332')
+
+  u, v = C.GF.loadb(x), C.GF.loadb(y)
+
+  g = u*v << 1
+  print 'y = %s' % words(g.storeb(48))
+  b1 = (g&repmask(0x01, 32, 6)) << 191
+  b2 = (g&repmask(0x03, 32, 6)) << 190
+  b7 = (g&repmask(0x7f, 32, 6)) << 185
+  b = b1 + b2 + b7
+  print 'b = %s' % words(b.storeb(48)[0:28])
+  h = g + b
+  print 'w = %s' % words(h.storeb(48))
+
+  a0 = (h&repmask(0xffffffff, 32, 6)) << 192
+  a1 = (h&repmask(0xfffffffe, 32, 6)) << 191
+  a2 = (h&repmask(0xfffffffc, 32, 6)) << 190
+  a7 = (h&repmask(0xffffff80, 32, 6)) << 185
+  a = a0 + a1 + a2 + a7
+
+  print '     a_1 = %s' % words(a1.storeb(48)[0:24])
+  print '     a_2 = %s' % words(a2.storeb(48)[0:24])
+  print '     a_7 = %s' % words(a7.storeb(48)[0:24])
+
+  print 'low+unit = %s' % words((h + a0).storeb(48)[0:24])
+  print ' low+0,2 = %s' % words((h + a0 + a2).storeb(48)[0:24])
+  print '     1,7 = %s' % words((a1 + a7).storeb(48)[0:24])
+
+  print 'a = %s' % words(a.storeb(48)[0:24])
+  z = h + a
+  print 'z = %s' % words(z.storeb(48))
+
+  z = gcm_mul(x, y)
+  print 'u v mod p = %s' % words(z)
+
+###--------------------------------------------------------------------------
+### Main program.
+
+style = argv[1]
+u = C.bytes(argv[2])
+v = C.bytes(argv[3])
+zz = DEMOMAP[style](u, v)
+assert zz == gcm_mul(u, v)
+
+###----- That's all, folks --------------------------------------------------