From: Mark Wooding Date: Wed, 6 May 2020 09:18:58 +0000 (+0100) Subject: Merge branch '2.5.x' X-Git-Tag: 2.6.0~50 X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/commitdiff_plain/7b0d1a63587f3cb1ae3bb8b248bbb1b82bdca7bd?hp=ac82eac807a9818e676c316f8afeab5cff2572cd Merge branch '2.5.x' * 2.5.x: vars.am: Don't build the test programs for installation. --- diff --git a/base/Makefile.am b/base/Makefile.am index 145f9c35..8b7c0fcd 100644 --- a/base/Makefile.am +++ b/base/Makefile.am @@ -45,6 +45,12 @@ libbase_la_SOURCES += ct.c ct-test.c ## CPU-specific dispatch. pkginclude_HEADERS += dispatch.h libbase_la_SOURCES += dispatch.c +if CPUFAM_X86 +libbase_la_SOURCES += dispatch-x86ish.S +endif +if CPUFAM_AMD64 +libbase_la_SOURCES += dispatch-x86ish.S +endif ## Acceptable key-size descriptions. pkginclude_HEADERS += keysz.h diff --git a/base/dispatch-x86ish.S b/base/dispatch-x86ish.S new file mode 100644 index 00000000..8c6a2a8f --- /dev/null +++ b/base/dispatch-x86ish.S @@ -0,0 +1,199 @@ +/// -*- mode: asm; asm-comment-char: ?/ -*- +/// +/// CPU dispatch support 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" + + EFLAGS_ID = 1 << 21 + + .text + +///-------------------------------------------------------------------------- +/// Probing for CPUID. + +FUNC(dispatch_x86ish_cpuid) + // Enter with a pointer to 16 bytes of storage for the output A, B, + // C, D values in the first argument, and input A and C values in the + // second and third. Fill the output buffer with `cpuid' results and + // return zero if we can; otherwise fill with zero and return -1. + +#if CPUFAM_X86 + pushreg ebx + pushreg edi + mov edi, [esp + 12] + mov eax, [esp + 16] + mov ecx, [esp + 20] +# define OUT edi +#endif +#if CPUFAM_AMD64 && ABI_SYSV + pushreg rbx + mov eax, esi + mov ecx, edx +# define OUT rdi +#endif +#if CPUFAM_AMD64 && ABI_WIN + pushreg rbx + mov r9, rcx + mov eax, edx + mov ecx, r8d +# define OUT r9 +#endif + endprologue + + // First, check that this is even a thing, using the complicated + // dance with the flags register. + pushf + pop R_d(r) // current flags in d + + or R_d(r), EFLAGS_ID // force the id bit on and check it + push R_d(r) + popf + pushf + pop R_d(r) + test edx, EFLAGS_ID + jz 8f + + and R_d(r), ~EFLAGS_ID // force the id bit off and check it + push R_d(r) + popf + pushf + pop R_d(r) + test edx, EFLAGS_ID + jnz 8f + + // OK, that seemed to work. + cpuid + + mov [OUT + 0], eax + mov [OUT + 4], ebx + mov [OUT + 8], ecx + mov [OUT + 12], edx + xor eax, eax + + // We're done. +9: +#if CPUFAM_X86 + popreg edi + popreg ebx +#endif +#if CPUFAM_AMD64 + popreg rbx +#endif + ret + + // Failed. +8: xor eax, eax + mov [OUT + 0], eax + mov [OUT + 4], eax + mov [OUT + 8], eax + mov [OUT + 12], eax + mov eax, -1 + jmp 9b +ENDFUNC + +///-------------------------------------------------------------------------- +/// Probing for XMM register availability. + +FUNC(dispatch_x86ish_xmmregisters_p) + // Enter with no arguments. Return nonzero if the XMM registers are + // usable. + + pushreg R_bp(r) + setfp + stalloc 512 + and R_sp(r), ~15 + endprologue + + // Save the floating point and SIMD registers, and try to clobber + // xmm0. + fxsave [R_sp(r)] + mov eax, [R_sp(r) + 160] + xor dword ptr [R_sp(r) + 160], 0xaaaa5555 + fxrstor [R_sp(r)] + + // Save them again, and read back the low word of xmm0. Undo the + // clobbering and restore. + fxsave [R_sp(r)] + mov ecx, [R_sp(r) + 160] + mov [R_sp(r) + 160], eax + fxrstor [R_sp(r)] + + // The register are live if we read different things. + xor eax, ecx + + // Done. + dropfp + popreg R_bp(r) + ret +ENDFUNC + +///-------------------------------------------------------------------------- +/// Checking `rdrand'. + +FUNC(dispatch_x86ish_rdrand) + // Enter with one argument: a pointer X_OUT to a 32-bit word. Try to + // generate a random word using `rdrand'. If successful, set *X_OUT + // to the generated word, and return zero; otherwise, return -1. + +#if CPUFAM_X86 +# define X_OUT edx +# define COUNT ecx + mov X_OUT, [esp + 4] +#endif +#if CPUFAM_AMD64 && ABI_SYSV +# define X_OUT rdi +# define COUNT ecx +#endif +#if CPUFAM_AMD64 && ABI_WIN +# define X_OUT rcx +# define COUNT edx +#endif + endprologue + + mov COUNT, 16 // fairly persistent +0: rdrand eax + jc 9f + dec COUNT + jnz 0b + + // Failed to come up with a random value. + mov eax, -1 + ret + + // Success. +9: mov [X_OUT], eax + xor eax, eax + ret + +#undef X_OUT +#undef COUNT + +ENDFUNC + +///----- That's all, folks -------------------------------------------------- diff --git a/base/dispatch.c b/base/dispatch.c index abd019f6..65ea2d25 100644 --- a/base/dispatch.c +++ b/base/dispatch.c @@ -43,7 +43,6 @@ #if CPUFAM_X86 || CPUFAM_AMD64 -# define EFLAGS_ID (1u << 21) # define CPUID1D_SSE2 (1u << 26) # define CPUID1D_FXSR (1u << 24) # define CPUID1C_PCLMUL (1u << 1) @@ -53,83 +52,18 @@ # define CPUID1C_RDRAND (1u << 30) struct cpuid { unsigned a, b, c, d; }; - -/* --- @cpuid@ --- * - * - * Arguments: @struct cpuid *cc@ = where to write the result - * @unsigned a, c@ = EAX and ECX registers to set - * - * Returns: --- - * - * Use: Minimal C wrapper around the x86 `CPUID' instruction. Checks - * that the instruction is actually available before invoking - * it; fills the output structure with zero if it's not going to - * work. - */ - -#ifdef __GNUC__ -# if CPUFAM_X86 -static __inline__ unsigned getflags(void) - { unsigned f; __asm__ ("pushf; popl %0" : "=g" (f)); return (f); } -static __inline__ unsigned setflags(unsigned f) -{ - unsigned ff; - __asm__ ("pushf; pushl %1; popf; pushf; popl %0; popf" - : "=r" (ff) - : "r" (f)); - return (ff); -} -# else -static __inline__ unsigned long getflags(void) - { unsigned long f; __asm__ ("pushf; popq %0" : "=g" (f)); return (f); } -static __inline__ unsigned long long setflags(unsigned long f) -{ - unsigned long ff; - __asm__ ("pushf; pushq %1; popf; pushf; popq %0; popf" - : "=r" (ff) - : "r" (f)); - return (ff); -} -# endif -#endif +extern int dispatch_x86ish_cpuid(struct cpuid *, unsigned a, unsigned c); +extern int dispatch_x86ish_xmmregisters_p(void); +extern int dispatch_x86ish_rdrand(unsigned *); static void cpuid(struct cpuid *cc, unsigned a, unsigned c) { -#ifdef __GNUC__ - unsigned f; -#endif - - cc->a = cc->b = cc->c = cc->d = 0; - -#ifdef __GNUC__ - /* Stupid dance to detect whether the CPUID instruction is available. */ - f = getflags(); - if (!(setflags(f | EFLAGS_ID) & EFLAGS_ID) || - setflags(f & ~EFLAGS_ID) & EFLAGS_ID) { + int rc = dispatch_x86ish_cpuid(cc, a, c); + if (rc) dispatch_debug("CPUID instruction not available"); - return; - } - setflags(f); - - /* Alas, EBX is magical in PIC code, so abuse ESI instead. This isn't - * pretty, but it works. - */ -# if CPUFAM_X86 - __asm__ ("pushl %%ebx; cpuid; movl %%ebx, %%esi; popl %%ebx" - : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d) - : "a" (a) , "c" (c)); -# elif CPUFAM_AMD64 - __asm__ ("pushq %%rbx; cpuid; movl %%ebx, %%esi; popq %%rbx" - : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d) - : "a" (a) , "c" (c)); -# else -# error "I'm confused." -# endif - dispatch_debug("CPUID(%08x, %08x) -> %08x, %08x, %08x, %08x", - a, c, cc->a, cc->b, cc->c, cc->d); -#else - dispatch_debug("GNU inline assembler not available; can't CPUID"); -#endif + else + dispatch_debug("CPUID(%08x, %08x) -> %08x, %08x, %08x, %08x", + a, c, cc->a, cc->b, cc->c, cc->d); } static unsigned cpuid_maxleaf(void) @@ -162,43 +96,10 @@ static int cpuid_features_p(unsigned dbits, unsigned cbits) static int xmm_registers_available_p(void) { -#ifdef __GNUC__ - unsigned f; - /* This hack is by Agner Fog. Use FXSAVE/FXRSTOR to figure out whether the - * XMM registers are actually alive. - */ - if (!cpuid_features_p(CPUID1D_FXSR, 0)) return (0); -# if CPUFAM_X86 - __asm__ ("movl %%esp, %%edx; subl $512, %%esp; andl $~15, %%esp\n" - "fxsave (%%esp)\n" - "movl 160(%%esp), %%eax; xorl $0xaaaa5555, 160(%%esp)\n" - "fxrstor (%%esp); fxsave (%%esp)\n" - "movl 160(%%esp), %%ecx; movl %%eax, 160(%%esp)\n" - "fxrstor (%%esp); movl %%edx, %%esp\n" - "xorl %%ecx, %%eax" - : "=a" (f) - : /* no inputs */ - : "%ecx", "%edx"); -# elif CPUFAM_AMD64 - __asm__ ("movq %%rsp, %%rdx; subq $512, %%rsp; andq $~15, %%rsp\n" - "fxsave (%%rsp)\n" - "movl 160(%%rsp), %%eax; xorl $0xaaaa5555, 160(%%rsp)\n" - "fxrstor (%%rsp); fxsave (%%rsp)\n" - "movl 160(%%rsp), %%ecx; movl %%eax, 160(%%rsp)\n" - "fxrstor (%%rsp); movq %%rdx, %%rsp\n" - "xorl %%ecx, %%eax" - : "=a" (f) - : /* no inputs */ - : "%ecx", "%rdx"); -# else -# error "I'm confused." -# endif + int f = dispatch_x86ish_xmmregisters_p(); + dispatch_debug("XMM registers %savailable", f ? "" : "not "); return (f); -#else - dispatch_debug("GNU inline assembler not available; can't check for XMM"); - return (0); -#endif } /* --- @rdrand_works_p@ --- * @@ -210,25 +111,6 @@ static int xmm_registers_available_p(void) * that it's already been verified to be safe to issue. */ -#ifdef __GNUC__ -static int rdrand(unsigned *x) -{ - int i, rc; - unsigned _t; - - i = 16; - __asm__ ("" : "=g" (_t)); - __asm__ ("0: rdrand %2; jc 1f; decl %1; jnz 0b\n" - "mov $-1, %0; jmp 9f\n" - "1: movl %2, (%3); xorl %0, %0\n" - "9:" - : "=r" (rc), "+r" (i), "+r" (_t) - : "r" (x) - : "cc"); - return (rc); -} -#endif - static int rdrand_works_p(void) { unsigned ref, x, i; @@ -237,9 +119,9 @@ static int rdrand_works_p(void) * will fail with probability %$2^{-128}$% with a truly random generator, * which seems fair enough. */ - if (rdrand(&ref)) goto fail; + if (dispatch_x86ish_rdrand(&ref)) goto fail; for (i = 0; i < 4; i++) { - if (rdrand(&x)) goto fail; + if (dispatch_x86ish_rdrand(&x)) goto fail; if (x != ref) goto not_stuck; } dispatch_debug("RDRAND always returns 0x%08x!", ref); diff --git a/base/keysz.h b/base/keysz.h index 4ad772a0..2986d614 100644 --- a/base/keysz.h +++ b/base/keysz.h @@ -59,7 +59,7 @@ enum { KSZ_ANY, /* Allows any key at all */ KSZ_RANGE, /* Allows keys within a range */ - KSZ_SET, /* Allows specific sizes of keys */ + KSZ_SET /* Allows specific sizes of keys */ }; #define KSZ_16BIT 0x20 /* Arguments are 16 bits long */ diff --git a/configure.ac b/configure.ac index b6c40ba5..b4f73896 100644 --- a/configure.ac +++ b/configure.ac @@ -423,7 +423,7 @@ dnl Set the master libraries we need. AC_SUBST([CATACOMB_LIBS]) dnl Necessary support libraries. -PKG_CHECK_MODULES([mLib], [mLib >= 2.3.0]) +PKG_CHECK_MODULES([mLib], [mLib >= 2.4.1]) AM_CFLAGS="$AM_CFLAGS $mLib_CFLAGS" dnl-------------------------------------------------------------------------- diff --git a/debian/.gitignore b/debian/.gitignore index b97ed0c2..4b961cd8 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -5,5 +5,6 @@ substvars *.debhelper catacomb catacomb-bin +catacomb-data catacomb-dev catacomb2 diff --git a/debian/catacomb2.symbols b/debian/catacomb2.symbols index 772d218e..33d5915a 100644 --- a/debian/catacomb2.symbols +++ b/debian/catacomb2.symbols @@ -24,6 +24,7 @@ libcatacomb.so.2 catacomb2 #MINVER# 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_rdrand@Base 2.5.99~ (optional|arch=i386 amd64)dispatch_x86ish_xmmregisters_p@Base 2.5.0 ## regdump (available with `--enable-asm-debug') diff --git a/debian/changelog b/debian/changelog index 066dcc59..db77dc17 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +catacomb (2.5.99~) experimental; urgency=medium + + * (placeholder for next minor release) + + -- Mark Wooding Mon, 30 Sep 2019 02:15:20 +0100 + catacomb (2.5.1) experimental; urgency=medium * Merge changes from 2.4.4. diff --git a/debian/control b/debian/control index c22c2559..89903a11 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: catacomb Section: libs Priority: extra Build-Depends: debhelper (>= 10), python, valgrind [!armel], pkg-config, - mlib-dev (>= 2.3.0) + mlib-dev (>= 2.4.1) Maintainer: Mark Wooding Standards-Version: 3.1.1 diff --git a/math/f25519.c b/math/f25519.c index a886465e..e9a91f41 100644 --- a/math/f25519.c +++ b/math/f25519.c @@ -183,7 +183,7 @@ void f25519_load(f25519 *z, const octet xv[32]) * and lower bounds are achievable. * * All of the x_i at this point are positive, so we don't need to do - * anything wierd when masking them. + * anything weird when masking them. */ b = x9&B24; c = 19&((b >> 19) - (b >> 24)); x9 -= b << 1; b = x8&B25; x9 += b >> 25; x8 -= b << 1; diff --git a/math/mpx.c b/math/mpx.c index 42948457..741cd9dc 100644 --- a/math/mpx.c +++ b/math/mpx.c @@ -818,7 +818,7 @@ void mpx_usub(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, void mpx_usubn(mpw *dv, mpw *dvl, mpw n) { MPX_USUBN(dv, dvl, n); } -/* --- @mpx_uaddnlsl@ --- * +/* --- @mpx_usubnlsl@ --- * * * Arguments: @mpw *dv, *dvl@ = destination and first argument vector * @mpw a@ = second argument diff --git a/rand/Makefile.am b/rand/Makefile.am index d97749e9..e02ccc59 100644 --- a/rand/Makefile.am +++ b/rand/Makefile.am @@ -67,6 +67,12 @@ librand_la_SOURCES += noise.c ## Cryptographic laundering for true random data generation. pkginclude_HEADERS += rand.h librand_la_SOURCES += rand.c +if CPUFAM_X86 +librand_la_SOURCES += rand-x86ish.S +endif +if CPUFAM_AMD64 +librand_la_SOURCES += rand-x86ish.S +endif librand_la_SOURCES += randgen.c ## The SSL v3 pseudorandom function. diff --git a/rand/lcrand.c b/rand/lcrand.c index 1c76f65b..f916c9c5 100644 --- a/rand/lcrand.c +++ b/rand/lcrand.c @@ -33,6 +33,7 @@ #include #include +#include #include #include "grand.h" @@ -106,15 +107,11 @@ uint32 lcrand(uint32 x) /* --- Now reduce mod p --- * * - * I'm using shifts and adds to do the multiply step here. This needs to - * be changed if @D@ ever becomes something other than 5. + * I'm using shifts and adds to do the multiply step here. */ -#if D != 5 -# error "Change shift sequence!" -#endif - { + STATIC_ASSERT(D == 5, "Shift sequence doesn't match prime"); uint32 q; q = yy[1]; diff --git a/rand/rand-x86ish.S b/rand/rand-x86ish.S new file mode 100644 index 00000000..829bc2cd --- /dev/null +++ b/rand/rand-x86ish.S @@ -0,0 +1,109 @@ +/// -*- mode: asm; asm-comment-char: ?/ -*- +/// +/// Random-number support 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" + + .extern F(rand_add) + + .text + +///-------------------------------------------------------------------------- +/// Quick random generation. + +FUNC(rand_quick_x86ish_rdrand) + // Enter with a pointer to the random context in the first argument. + // Return zero on success, or -1 on error. + +#if CPUFAM_X86 + mov edx, [esp + 4] + stalloc 28 +# define COUNT ecx +#endif +#if CPUFAM_AMD64 && ABI_SYSV + stalloc 8 +# define COUNT ecx +#endif +#if CPUFAM_AMD64 && ABI_WIN + stalloc 40 +# define COUNT r8d +#endif + endprologue + + // Try to fetch a random number. + mov COUNT, 16 +0: rdrand R_a(r) + jc 1f + dec COUNT + jnz 0b + + // Failed. + mov eax, -1 + jmp 9f + + // Success. +1: +#if CPUFAM_X86 + mov [esp + 16], eax + lea ecx, [esp + 16] + mov dword ptr [esp + 12], 32 + mov dword ptr [esp + 8], 4 + mov [esp + 4], ecx + mov [esp + 0], edx +#endif +#if CPUFAM_AMD64 && ABI_SYSV + mov [rsp + 0], rax + mov rsi, rsp + mov edx, 8 + mov ecx, 64 +#endif +#if CPUFAM_AMD64 && ABI_WIN + mov [rsp + 32], rax + lea rdx, [rsp + 32] + mov r8d, 8 + mov r9d, 64 +#endif + callext F(rand_add) + xor eax, eax + + // Done. +9: +#if CPUFAM_X86 + stfree 28 +#endif +#if CPUFAM_AMD64 && ABI_SYSV + stfree 8 +#endif +#if CPUFAM_AMD64 && ABI_WIN + stfree 40 +#endif + ret +ENDFUNC + +///----- That's all, folks -------------------------------------------------- diff --git a/rand/rand.c b/rand/rand.c index 6787c11a..32605ac0 100644 --- a/rand/rand.c +++ b/rand/rand.c @@ -161,24 +161,14 @@ CPU_DISPATCH(static, return, int, quick, (rand_pool *r), (r), static int trivial_quick(rand_pool *r) { return (-1); } -#if __GNUC__ && (CPUFAM_X86 || CPUFAM_AMD64) -static int rdrand_quick(rand_pool *r) -{ - unsigned long rr; - int i = 16; - - __asm__ ("0: rdrand %0; jc 9f; dec %1; jnz 0b; 9:" - : "=r" (rr), "=r" (i) : "1" (i) : "cc"); - if (!i) return (-1); - rand_add(r, &rr, sizeof(rr), 8*sizeof(rr)); - return (0); -} +#if CPUFAM_X86 || CPUFAM_AMD64 +extern int rand_quick_x86ish_rdrand(rand_pool */*r*/); #endif static quick__functype *pick_quick(void) { -#if __GNUC__ && (CPUFAM_X86 || CPUFAM_AMD64) - DISPATCH_PICK_COND(rand_quick, rdrand_quick, +#if CPUFAM_X86 || CPUFAM_AMD64 + DISPATCH_PICK_COND(rand_quick, rand_quick_x86ish_rdrand, cpu_feature_p(CPUFEAT_X86_RDRAND)); #endif DISPATCH_PICK_FALLBACK(rand_quick, trivial_quick); @@ -261,9 +251,7 @@ void rand_add(rand_pool *r, const void *p, size_t sz, unsigned goodbits) const octet *c = p; int i, rot; -#if RAND_POOLSZ != 128 -# error Polynomial in rand_add is out of date. Fix it. -#endif + STATIC_ASSERT(RAND_POOLSZ == 128, "Polynomial doesn't match pool size"); RAND_RESOLVE(r); diff --git a/symm/keccak1600.c b/symm/keccak1600.c index d58bc6f8..499ab4f6 100644 --- a/symm/keccak1600.c +++ b/symm/keccak1600.c @@ -221,6 +221,8 @@ static const lane rcon[24] = { * `keccak1600_round' below for the details. */ +#define COMPL_MASK 0x00121106u + #define STATE_INIT(z) do { \ lane cmpl = LANE_CMPL; \ (z)->S[I(1, 0)] = cmpl; (z)->S[I(2, 0)] = cmpl; \ @@ -240,6 +242,8 @@ static const lane rcon[24] = { #else /* A target with fused and/not (`bic', `andc2'). Everything is simple. */ +#define COMPL_MASK 0u + #define STATE_INIT(z) do ; while (0) #define STATE_OUT(z) do ; while (0) @@ -600,11 +604,14 @@ void keccak1600_mix(keccak1600_state *s, const kludge64 *p, size_t n) void keccak1600_extract(const keccak1600_state *s, kludge64 *p, size_t n) { + uint32 m = COMPL_MASK; unsigned i; - keccak1600_state t; + lane t; - t = *s; STATE_OUT(&t); - for (i = 0; i < n; i++) p[i] = FROM_LANE(t.S[i]); + for (i = 0; i < n; i++) { + t = s->S[i]; if (m&1) NOT_LANE(t, t); + *p++ = FROM_LANE(t); m >>= 1; + } } /*----- Test rig ----------------------------------------------------------*/